简体   繁体   English

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

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

Pretty straightforward question: Given an N x N symmetric matrix A and an N-vector x, is there a built-in Matlab function to calculate x'*A*x ? 非常简单的问题:给定N×N对称矩阵A和N向量x,是否有内置的Matlab函数来计算x'*A*x ie, instead of y = x'*A*x , is there a function quadraticform st y = quadraticform(A, x) ? 即,代替y = x'*A*x ,是否存在函数quadraticform st y = quadraticform(A, x)

Obviously I can just do y = x'*A*x , but I need performance and it seems like there ought to be a way to take advantage of 显然我可以做y = x'*A*x ,但我需要表现,似乎应该有办法利用

  1. A is symmetric A是对称的
  2. The left and right multipliers are the same vector 左右乘数是相同的向量

If there's not a single built-in function, is there method that's faster than x'*A*x ? 如果没有单一的内置函数,是否有比x'*A*x更快的方法? OR, is the Matlab parser smart enough to optimize x'*A*x ? 或者,Matlab解析器是否足够智能以优化x'*A*x If so, can you point me to a place in the documentation that verifies the fact? 如果是这样,你能指点我在文件中的一个地方验证这个事实吗?

I couldn't find such a built-in function, and I have an idea why. 我找不到这样的内置函数,我知道为什么。

y=x'*A*x can be written as a sum of n^2 terms A(i,j)*x(i)*x(j) , where i and j runs from 1 to n (where A is an nxn matrix). y=x'*A*x可以写成n^2A(i,j)*x(i)*x(j) ,其中ij1n (其中A是a) nxn矩阵)。 A is symmetric: A(i,j) = A(j,i) for all i and j . A是对称的:对于所有ij A(i,j) = A(j,i) Due to symmetry, every term appears twice in the sum, except for those where i equals j . 由于对称性,每个项在总和中出现两次,除了那些i等于j So we have n*(n+1)/2 different terms. 所以我们有n*(n+1)/2不同的术语。 Each has two floating-point multiplications, so a naive method would need n*(n+1) multiplications in total. 每个都有两个浮点乘法,所以一个朴素的方法总共需要n*(n+1)乘法。 It is easy to see that the naive calculation of x'*A*x , that is, calculating z=A*x and then y=x'*z , also needs n*(n+1) multiplications. 很容易看出, x'*A*x的朴素计算,即计算z=A*x ,然后计算y=x'*z ,也需要n*(n+1)乘法。 However, there is a faster way to sum our n*(n+1)/2 different terms: for every i , we can factor out x(i) , which means that only n*(n-1)/2+3*n multiplications is enough. 然而,有一种更快的方法来求和我们的n*(n+1)/2不同的项:对于每个i ,我们可以分解x(i) ,这意味着只有n*(n-1)/2+3*n乘法就足够了。 But this does not really help: the running time of the calculation of y=x'*A*x is still O(n^2) . 但这并没有真正帮助: y=x'*A*x的计算运行时间仍为O(n^2)

So, I think that the calculation of quadratic forms cannot be done faster than O(n^2) , and since this can also be achieved by the formula y=x'*A*x , there would be no real advantage of a special "quadraticform" function. 因此,我认为二次形式的计算不能比O(n^2)更快地完成,并且因为这也可以通过公式y=x'*A*x ,所以没有特殊的优势。 “二次型”功能。

=== UPDATE === ===更新===

I've written the function "quadraticform" in C, as a Matlab extension: 我在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);
}

I saved this code as "quadraticform.c", and compiled it with Matlab: 我将此代码保存为“quadraticform.c”,并使用Matlab编译:

mex -O quadraticform.c

I wrote a simple performance test to compare this function with x' A x: 我写了一个简单的性能测试这一功能与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');

The result is very interesting. 结果非常有趣。 The running time of both x'*A*x and quadraticform(A,x) converges to O(n^2) , but the former has a smaller factor: x'*A*xquadraticform(A,x)的运行时间收敛到O(n^2) ,但前者的因子较小:

quadraticformtest.png

MATLAB is clever enough to recognise and optimise some sorts of compound matrix expression, and I believe (although I can't definitely confirm) that the quadratic form is one of the optimisations that it does make. MATLAB足够聪明地识别和优化某些复合矩阵表达式,我相信(尽管我无法确定)二次型是它确实做出的优化之一。

However, it's not the sort of thing MathWorks tend to document, because a) it will typically only be optimised within functions, not in scripts, at the command line or in debugging b) it may only work in some circumstances, such as for real nonsparse A c) it may change from release to release, so they don't want you to rely on it d) it's one of the proprietary things that make MATLAB so good. 但是,它不是MathWorks倾向于记录的东西,因为a)它通常只在函数内优化,而不是在脚本中,在命令行或调试中优化b)它可能只在某些情况下工作,例如真实nonsparse A c)它可能会在不同版本之间发生变化,因此它们不希望您依赖它.d)它是使MATLAB如此优秀的专有事物之一。

To confirm, you could try comparing timings for y=x'*A*x against B=A*x; y=x'*B 要确认,您可以尝试将y=x'*A*xB=A*x; y=x'*B B=A*x; y=x'*B . B=A*x; y=x'*B You could also try feature('accel','off') , which will turn most of those sort of optimisations off. 您还可以尝试使用feature('accel','off') ,这将关闭大部分优化功能。

Finally, if you contact MathWorks support, you might be able to get one of the developers to confirm whether the optimisation is being made. 最后,如果您联系MathWorks支持,您可以让其中一位开发人员确认是否正在进行优化。

I'm not sure if this will work in your case, but I came across a similar situation where I wanted to calculate many sums of squares. 我不确定这是否适用于您的情况,但我遇到了类似的情况,我想计算许多平方和。 After tinkering with the algebra, I realized I was approaching this like a mathematician and not like a computer engineer: 在修补代数之后,我意识到我像数学家一样接近这个而不是像计算机工程师那样:

If the rows of X are your data points, then the i th row of Q below will be the i th sum: 如果行X是你的数据点,那么第i的行Q之下将是个求和

Q = sum(X.^2 * A)

Hope that helps! 希望有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM