簡體   English   中英

是否有內置的matlab計算二次形式(x'* A * x)?

[英]Is there a matlab built-in that calculates the quadratic form (x'*A*x)?

非常簡單的問題:給定N×N對稱矩陣A和N向量x,是否有內置的Matlab函數來計算x'*A*x 即,代替y = x'*A*x ,是否存在函數quadraticform st y = quadraticform(A, x)

顯然我可以做y = x'*A*x ,但我需要表現,似乎應該有辦法利用

  1. A是對稱的
  2. 左右乘數是相同的向量

如果沒有單一的內置函數,是否有比x'*A*x更快的方法? 或者,Matlab解析器是否足夠智能以優化x'*A*x 如果是這樣,你能指點我在文件中的一個地方驗證這個事實嗎?

我找不到這樣的內置函數,我知道為什么。

y=x'*A*x可以寫成n^2A(i,j)*x(i)*x(j) ,其中ij1n (其中A是a) nxn矩陣)。 A是對稱的:對於所有ij A(i,j) = A(j,i) 由於對稱性,每個項在總和中出現兩次,除了那些i等於j 所以我們有n*(n+1)/2不同的術語。 每個都有兩個浮點乘法,所以一個朴素的方法總共需要n*(n+1)乘法。 很容易看出, x'*A*x的朴素計算,即計算z=A*x ,然后計算y=x'*z ,也需要n*(n+1)乘法。 然而,有一種更快的方法來求和我們的n*(n+1)/2不同的項:對於每個i ,我們可以分解x(i) ,這意味着只有n*(n-1)/2+3*n乘法就足夠了。 但這並沒有真正幫助: y=x'*A*x的計算運行時間仍為O(n^2)

因此,我認為二次形式的計算不能比O(n^2)更快地完成,並且因為這也可以通過公式y=x'*A*x ,所以沒有特殊的優勢。 “二次型”功能。

===更新===

我在C中寫了函數“quadraticform”,作為Matlab擴展:

// y = quadraticform(A, x)
#include "mex.h" 

/* Input Arguments */
#define A_in prhs[0]
#define x_in prhs[1]

/* Output Arguments */
#define y_out plhs[0] 

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
  mwSize mA, nA, n, mx, nx;
  double *A, *x;
  double z, y;
  int i, j, k;

  if (nrhs != 2) { 
      mexErrMsgTxt("Two input arguments required."); 
  } else if (nlhs > 1) {
      mexErrMsgTxt("Too many output arguments."); 
  }

  mA = mxGetM(A_in);
  nA = mxGetN(A_in);
  if (mA != nA)
    mexErrMsgTxt("The first input argument must be a quadratic matrix.");
  n = mA;

  mx = mxGetM(x_in);
  nx = mxGetN(x_in);
  if (mx != n || nx != 1)
    mexErrMsgTxt("The second input argument must be a column vector of proper size.");

  A = mxGetPr(A_in);
  x = mxGetPr(x_in);
  y = 0.0;
  k = 0;
  for (i = 0; i < n; ++i)
  {
    z = 0.0;
    for (j = 0; j < i; ++j)
      z += A[k + j] * x[j];
    z *= x[i];
    y += A[k + i] * x[i] * x[i] + z + z;
    k += n;
  }

  y_out = mxCreateDoubleScalar(y);
}

我將此代碼保存為“quadraticform.c”,並使用Matlab編譯:

mex -O quadraticform.c

我寫了一個簡單的性能測試這一功能與X” X比較:

clear all; close all; clc;

sizes = int32(logspace(2, 3, 25));
nsizes = length(sizes);
etimes = zeros(nsizes, 2); % Matlab vs. C
nrepeats = 100;
h = waitbar(0, 'Please wait...');
for i = 1 : nrepeats
  for j = 1 : nsizes
    n = sizes(j);
    A = randn(n); 
    A = (A + A') / 2;
    x = randn(n, 1);
    if randn > 0
      start = tic;
      y1 = x' * A * x;
      etimes(j, 1) = etimes(j, 1) + toc(start);
      start = tic;
      y2 = quadraticform(A, x);
      etimes(j, 2) = etimes(j, 2) + toc(start);      
    else
      start = tic;
      y2 = quadraticform(A, x);
      etimes(j, 2) = etimes(j, 2) + toc(start);      
      start = tic;
      y1 = x' * A * x;
      etimes(j, 1) = etimes(j, 1) + toc(start);
    end;
    if abs((y1 - y2) / y2) > 1e-10
      error('"x'' * A * x" is not equal to "quadraticform(A, x)"');
    end;
    waitbar(((i - 1) * nsizes + j) / (nrepeats * nsizes), h);
  end;
end;
close(h);
clear A x y;
etimes = etimes / nrepeats;

n = double(sizes);
n2 = n .^ 2.0;
i = nsizes - 2 : nsizes;
n2_1 = mean(etimes(i, 1)) * n2 / mean(n2(i));
n2_2 = mean(etimes(i, 2)) * n2 / mean(n2(i));

figure;
loglog(n, etimes(:, 1), 'r.-', 'LineSmoothing', 'on');
hold on;
loglog(n, etimes(:, 2), 'g.-', 'LineSmoothing', 'on');
loglog(n, n2_1, 'k-', 'LineSmoothing', 'on');
loglog(n, n2_2, 'k-', 'LineSmoothing', 'on');
axis([n(1) n(end) 1e-4 1e-2]);
xlabel('Matrix size, n');
ylabel('Running time (a.u.)');
legend('x'' * A * x', 'quadraticform(A, x)', 'O(n^2)', 'Location', 'NorthWest');

W = 16 / 2.54; H = 12 / 2.54; dpi = 100;
set(gcf, 'PaperPosition', [0, 0, W, H]);
set(gcf, 'PaperSize', [W, H]);
print(gcf, sprintf('-r%d',dpi), '-dpng', 'quadraticformtest.png');

結果非常有趣。 x'*A*xquadraticform(A,x)的運行時間收斂到O(n^2) ,但前者的因子較小:

quadraticformtest.png

MATLAB足夠聰明地識別和優化某些復合矩陣表達式,我相信(盡管我無法確定)二次型是它確實做出的優化之一。

但是,它不是MathWorks傾向於記錄的東西,因為a)它通常只在函數內優化,而不是在腳本中,在命令行或調試中優化b)它可能只在某些情況下工作,例如真實nonsparse A c)它可能會在不同版本之間發生變化,因此它們不希望您依賴它.d)它是使MATLAB如此優秀的專有事物之一。

要確認,您可以嘗試將y=x'*A*xB=A*x; y=x'*B B=A*x; y=x'*B 您還可以嘗試使用feature('accel','off') ,這將關閉大部分優化功能。

最后,如果您聯系MathWorks支持,您可以讓其中一位開發人員確認是否正在進行優化。

我不確定這是否適用於您的情況,但我遇到了類似的情況,我想計算許多平方和。 在修補代數之后,我意識到我像數學家一樣接近這個而不是像計算機工程師那樣:

如果行X是你的數據點,那么第i的行Q之下將是個求和

Q = sum(X.^2 * A)

希望有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM