gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 20:16:53 24 4
gpt4 key购买 nike

非常简单的问题:给定一个 N x N 对称矩阵 A 和一个 N 向量 x,是否有内置的 Matlab 函数来计算 x'*A*x?即,不是 y = x'*A*x,是否有函数 quadraticform s.t. 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),其中 ij1 运行到 n(其中 A 是一个 nxn 矩阵)。 A 是对称的:A(i,j) = A(j,i) 对于所有 ij .由于对称性,除 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'Ax:

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

关于performance - 是否有内置的 matlab 可以计算二次形式 (x'*A*x)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8369832/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com