如何创建一个对称矩阵,其中每个 row/column 都是已知向量的子集
How to create a symmetric matrix where each row/column is a subset of a known vector
我有一个 7*1 向量 a = (1:7).'
。我想从向量 a
形成一个大小为 4*4 的矩阵 A
,这样 a
的元素形成矩阵 A
的反对角线,如下所示:
A = [1 2 3 4;
2 3 4 5;
3 4 5 6;
4 5 6 7]
我希望这适用于一般 a
,而不仅仅是当元素是连续整数时。
感谢任何帮助。
设置索引
将meshgrid
的两个输出相加可以得到索引:
[x, y] = meshgrid(1:4, 0:3);
x + y;
% ans = [1 2 3 4
% 2 3 4 5
% 3 4 5 6
% 4 5 6 7];
如果 a
与您的示例一样,您可以到此为止。或者,使用它来索引一般向量 a
。为了进行比较,我将使用与 rahnema1 为他们的方法所做的相同的示例输入:
a = [4 6 2 7 3 5 1];
[x, y] = meshgrid(1:4, 0:3);
A = a(x + y);
% A = [4 6 2 7
% 6 2 7 3
% 2 7 3 5
% 7 3 5 1]
有 许多 种方法可以创建索引而不是使用 meshgrid
,请参阅下面的基准测试函数以获取一些示例!
基准测试和七种不同的方法。
这里是 运行 不同方法的一些计时,包括使用 cumsum
、repmat
、hankel
的方法和简单的 for
循环。该基准测试是在 Matlab 2015b 中完成的,因此利用了 Matlab 优化等,而 rahnema1 答案中的 Octave 基准测试可能无法做到。我还使用了比 tic
/toc
更强大的 timeit
函数,因为它进行了多次试验等
function benchie()
n = 10000; % (large) square matrix size
a = 1:2*n-1; % array of correct size, could be anything this long
f1 = @() m1(a,n); disp(['bsxfun: ', num2str(timeit(f1))]);
f2 = @() m2(a,n); disp(['cumsum: ', num2str(timeit(f2))]);
f3 = @() m3(a,n); disp(['meshgrid: ', num2str(timeit(f3))]);
f4 = @() m4(a,n); disp(['repmat: ', num2str(timeit(f4))]);
f5 = @() m5(a,n); disp(['for loop: ', num2str(timeit(f5))]);
f6 = @() m6(a,n); disp(['hankel1: ', num2str(timeit(f6))]);
f7 = @() m7(a,n); disp(['hankel2: ', num2str(timeit(f7))]);
end
% Use bsxfun to do broadcasting of addition
function m1(a,n); A = a(bsxfun(@plus, (1:n), (0:n-1).')); end
% Use cumsum to do cumulative vertical addition to create indices
function m2(a,n); A = a(cumsum([(1:n); ones(n-1,n)])); end
% Add the two meshgrid outputs to get indices
function m3(a,n); [x, y] = meshgrid(1:n, 0:n-1); A = a(x + y); end
% Use repmat twice to replicate the meshgrid results, for equivalent one liner
function m4(a,n); A = a(repmat((1:n)',1,n) + repmat(0:n-1,n,1)); end
% Use a simple for loop. Initialise A and assign values to each row in turn
function m5(a,n); A = zeros(n); for ii = 1:n; A(:,ii) = a(ii:ii+n-1); end; end
% Create a Hankel matrix (constant along anti-diagonals) for indexing
function m6(a,n); A = a(hankel(1:n,n:2*n-1)); end
% Create a Hankel matrix directly from elements
function m7(a,n); A = hankel(a(1:n),a(n:2*n-1)); end
输出:
bsxfun: 1.4397 sec
cumsum: 2.0563 sec
meshgrid: 2.0169 sec
repmat: 1.8598 sec
for loop: 0.4953 sec % MUCH quicker!
hankel1: 2.6154 sec
hankel2: 1.4235 sec
所以你最好使用 rahnema1 的建议 bsxfun
或直接生成 hankel
矩阵,如果你想要一个衬垫,这里有一个很棒的 Whosebug 答案,它解释了 bsxfun
的优点:In Matlab, when is it optimal to use bsxfun?
然而,for 循环的速度是原来的两倍多! 结论:Matlab 有很多巧妙的方法来实现这样的事情,有时一个简单的 for 循环加上一些适当的预定义-分配和 Matlab 的内部优化可能是最快的。
您可以使用 hankel
:
n= 4;
A= hankel(a(1:n),a(n:2*n-1))
其他解决方案(expansion/bsxfun):
在MATLAB r2016b /Octave中可以创建为:
A = a((1:4)+(0:3).')
在 r2016b 之前你可以使用 bsxfun
:
A = a(bsxfun(@plus,1:4, (0:3).'))
示例input/output
a = [4 6 2 7 3 5 1]
A =
4 6 2 7
6 2 7 3
2 7 3 5
7 3 5 1
使用@Wolfie 提供的基准在 Octave 中测试:
_____________________________________
|Method |memory peak(MB)|timing(Sec)|
|=========|===============|===========|
|bsxfun |2030 |1.50 |
|meshgrid |3556 |2.43 |
|repmat |2411 |2.64 |
|hankel |886 |0.43 |
|for loop |886 |0.82 |
我有一个 7*1 向量 a = (1:7).'
。我想从向量 a
形成一个大小为 4*4 的矩阵 A
,这样 a
的元素形成矩阵 A
的反对角线,如下所示:
A = [1 2 3 4;
2 3 4 5;
3 4 5 6;
4 5 6 7]
我希望这适用于一般 a
,而不仅仅是当元素是连续整数时。
感谢任何帮助。
设置索引
将meshgrid
的两个输出相加可以得到索引:
[x, y] = meshgrid(1:4, 0:3);
x + y;
% ans = [1 2 3 4
% 2 3 4 5
% 3 4 5 6
% 4 5 6 7];
如果 a
与您的示例一样,您可以到此为止。或者,使用它来索引一般向量 a
。为了进行比较,我将使用与 rahnema1 为他们的方法所做的相同的示例输入:
a = [4 6 2 7 3 5 1];
[x, y] = meshgrid(1:4, 0:3);
A = a(x + y);
% A = [4 6 2 7
% 6 2 7 3
% 2 7 3 5
% 7 3 5 1]
有 许多 种方法可以创建索引而不是使用 meshgrid
,请参阅下面的基准测试函数以获取一些示例!
基准测试和七种不同的方法。
这里是 运行 不同方法的一些计时,包括使用 cumsum
、repmat
、hankel
的方法和简单的 for
循环。该基准测试是在 Matlab 2015b 中完成的,因此利用了 Matlab 优化等,而 rahnema1 答案中的 Octave 基准测试可能无法做到。我还使用了比 tic
/toc
更强大的 timeit
函数,因为它进行了多次试验等
function benchie()
n = 10000; % (large) square matrix size
a = 1:2*n-1; % array of correct size, could be anything this long
f1 = @() m1(a,n); disp(['bsxfun: ', num2str(timeit(f1))]);
f2 = @() m2(a,n); disp(['cumsum: ', num2str(timeit(f2))]);
f3 = @() m3(a,n); disp(['meshgrid: ', num2str(timeit(f3))]);
f4 = @() m4(a,n); disp(['repmat: ', num2str(timeit(f4))]);
f5 = @() m5(a,n); disp(['for loop: ', num2str(timeit(f5))]);
f6 = @() m6(a,n); disp(['hankel1: ', num2str(timeit(f6))]);
f7 = @() m7(a,n); disp(['hankel2: ', num2str(timeit(f7))]);
end
% Use bsxfun to do broadcasting of addition
function m1(a,n); A = a(bsxfun(@plus, (1:n), (0:n-1).')); end
% Use cumsum to do cumulative vertical addition to create indices
function m2(a,n); A = a(cumsum([(1:n); ones(n-1,n)])); end
% Add the two meshgrid outputs to get indices
function m3(a,n); [x, y] = meshgrid(1:n, 0:n-1); A = a(x + y); end
% Use repmat twice to replicate the meshgrid results, for equivalent one liner
function m4(a,n); A = a(repmat((1:n)',1,n) + repmat(0:n-1,n,1)); end
% Use a simple for loop. Initialise A and assign values to each row in turn
function m5(a,n); A = zeros(n); for ii = 1:n; A(:,ii) = a(ii:ii+n-1); end; end
% Create a Hankel matrix (constant along anti-diagonals) for indexing
function m6(a,n); A = a(hankel(1:n,n:2*n-1)); end
% Create a Hankel matrix directly from elements
function m7(a,n); A = hankel(a(1:n),a(n:2*n-1)); end
输出:
bsxfun: 1.4397 sec
cumsum: 2.0563 sec
meshgrid: 2.0169 sec
repmat: 1.8598 sec
for loop: 0.4953 sec % MUCH quicker!
hankel1: 2.6154 sec
hankel2: 1.4235 sec
所以你最好使用 rahnema1 的建议 bsxfun
或直接生成 hankel
矩阵,如果你想要一个衬垫,这里有一个很棒的 Whosebug 答案,它解释了 bsxfun
的优点:In Matlab, when is it optimal to use bsxfun?
然而,for 循环的速度是原来的两倍多! 结论:Matlab 有很多巧妙的方法来实现这样的事情,有时一个简单的 for 循环加上一些适当的预定义-分配和 Matlab 的内部优化可能是最快的。
您可以使用 hankel
:
n= 4;
A= hankel(a(1:n),a(n:2*n-1))
其他解决方案(expansion/bsxfun):
在MATLAB r2016b /Octave中可以创建为:
A = a((1:4)+(0:3).')
在 r2016b 之前你可以使用 bsxfun
:
A = a(bsxfun(@plus,1:4, (0:3).'))
示例input/output
a = [4 6 2 7 3 5 1]
A =
4 6 2 7
6 2 7 3
2 7 3 5
7 3 5 1
使用@Wolfie 提供的基准在 Octave 中测试:
_____________________________________
|Method |memory peak(MB)|timing(Sec)|
|=========|===============|===========|
|bsxfun |2030 |1.50 |
|meshgrid |3556 |2.43 |
|repmat |2411 |2.64 |
|hankel |886 |0.43 |
|for loop |886 |0.82 |