[英]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
,但我需要表现,似乎应该有办法利用
A
是对称的 如果没有单一的内置函数,是否有比x'*A*x
更快的方法? 或者,Matlab解析器是否足够智能以优化x'*A*x
? 如果是这样,你能指点我在文件中的一个地方验证这个事实吗?
我找不到这样的内置函数,我知道为什么。
y=x'*A*x
可以写成n^2
项A(i,j)*x(i)*x(j)
,其中i
和j
从1
到n
(其中A
是a) nxn
矩阵)。 A
是对称的:对于所有i
和j
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*x
和quadraticform(A,x)
的运行时间收敛到O(n^2)
,但前者的因子较小:
MATLAB足够聪明地识别和优化某些复合矩阵表达式,我相信(尽管我无法确定)二次型是它确实做出的优化之一。
但是,它不是MathWorks倾向于记录的东西,因为a)它通常只在函数内优化,而不是在脚本中,在命令行或调试中优化b)它可能只在某些情况下工作,例如真实nonsparse A c)它可能会在不同版本之间发生变化,因此它们不希望您依赖它.d)它是使MATLAB如此优秀的专有事物之一。
要确认,您可以尝试将y=x'*A*x
与B=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.