MATLAB: efficient generating of block matrices using a block vector - matlab

Suppose
x = [x1;x2; ...; xn]
where each xi is a column vector with length l(i). We can set L = sum(l), the total length of x. I would like to generate 2 matrices based on x:
Let's call them A and B. For example, when x only as 2 blocks x1 and x2 then:
A = [x1*x1' zeros(l(1),l(2)); zeros(l(2),l(1)), x2*x2'];
B = [x1 zeros(l(1),1);
zeros(l(2),1), x2];
In the notation of the problem, A is always L by L and B is L by n. I can generate A and B given x using loops but it is tedious. Is there a clever (loop-free) way to generate A and B. I am using MATLAB 2018b but you can assume earlier version of MATLAB if necessary.

I think it is both short and fast:
B = x .* (repelem((1:numel(l)).',l)==(1:numel(l)));
A = B * B.';
If you have large data It is better to use sparse matrix:
B = sparse(1:numel(x), repelem(1:numel(l), l), x);
A = B * B.';

The following should work. In this case I do an inefficient conversion to cell arrays so there may be a more efficient implementation possible.
cuml = [0; cumsum(l(:))];
get_x = #(idx) x((1:l(idx))+cuml(idx));
x_cell = arrayfun(get_x, 1:numel(l), 'UniformOutput', false);
B = blkdiag(x_cell{:});
A = B*B';
Edit
After running some benchmarks I found a direct loop based implementation to be about twice as fast as the cell based approach above.
A = zeros(sum(l));
B = zeros(sum(l), numel(l));
prev = 0;
for idx = 1:numel(l)
xidx = (1:l(idx))+prev;
A(xidx, xidx) = x(xidx,1) * x(xidx,1)';
B(xidx, idx) = x(idx,1);
prev = prev + l(idx);
end

Here's an alternative approach:
s = repelem(1:numel(l), l).';
t = accumarray(s, x, [], #(x){x*x'});
A = blkdiag(t{:});
t = accumarray(s, x, [], #(x){x});
B = blkdiag(t{:});

Related

Memory usage by Matlab

I'm running a Matlab code in the HPC of my university. I have two versions of the code. The second version, despite generating a smaller array, seems to require more memory. I would like your help to understand if this is in fact the case and why.
Let me start from some preliminary lines:
clear
rng default
%Some useful components
n=7^4;
vectors{1}=[1,20,20,20,-1,Inf,-Inf];
vectors{2}=[-19,19,19,19,-20,Inf,-Inf];
vectors{3}=[-19,0,0,0,-20,Inf,-Inf];
vectors{4}=[-19,0,0,0,-20,Inf,-Inf];
T_temp = cell(1,4);
[T_temp{:}] = ndgrid(vectors{:});
T_temp = cat(4+1, T_temp{:});
T = reshape(T_temp,[],4); %all the possible 4-tuples from vectors{1}, ..., vectors{4}
This is the first version 1 of the code: I construct the matrix D1 listing all possible pairs of unordered rows from T
indices_pairs=pairIndices(n);
D1=[T(indices_pairs(:,1),:) T(indices_pairs(:,2),:)];
This is the second version of the code: I construct the matrix D2 listing a random draw of m=10^6 unordered pairs of rows from T
m=10^6;
p=n*(n-1)/2;
random_indices_pairs = randperm(p, m).';
[C1, C2] = myind2ind (random_indices_pairs, n);
indices_pairs=[C1 C2];
D2=[T(indices_pairs(:,1),:) T(indices_pairs(:,2),:)];
My question: when generating D2 the HPC goes out of memory. When generating D1 the HPC works fine, despite D1 being a larger array than D2. Why is that the case?
These are complementary functions used above:
function indices = pairIndices(n)
[y, x] = find(tril(logical(ones(n)), -1)); %#ok<LOGL>
indices = [x, y];
end
function [R , C] = myind2ind(ii, N)
jj = N * (N - 1) / 2 + 1 - ii;
r = (1 + sqrt(8 * jj)) / 2;
R = N -floor(r);
idx_first = (floor(r + 1) .* floor(r)) / 2;
C = idx_first-jj + R + 1;
end

How to plot a function of multiple variables in Matlab?

I'm trying to figure out a way to make a plot of a function in Matlab that accepts k parameters and returns a 3D point. Currently I've got this working for two variables m and n. How can I expand this process to any number of parameters?
K = zeros(360*360, number);
for m = 0:5:359
for n = 1:5:360
K(m*360 + n, 1) = cosd(m)+cosd(m+n);
K(m*360 + n, 2) = sind(m)+sind(m+n);
K(m*360 + n, 3) = cosd(m)+sind(m+n);
end
end
K(all(K==0,2),:)=[];
plot3(K(:,1),K(:,2),K(:,3),'.');
end
The code you see above is for a similar problem but not exactly the same.
Most of the time you can do this in a vectorized manner by using ndgrid.
[M, N] = ndgrid(0:5:359, 1:5:360);
X = cosd(M)+cosd(M+N);
Y = sind(M)+sind(M+N);
Z = cosd(M)+sind(M+N);
allZero = (X==0)&(Y==0)&(Z==0); % This ...
X(allZero) = []; % does not ...
Y(allZero) = []; % do ...
Z(allZero) = []; % anything.
plot3(X,Y,Z,'b.');
A little explanation:
The call [M, N] = ndgrid(0:5:359, 1:5:360); generates all combinations, where M is an element of 0:5:359 and N is an element of 1:5:360. This will be in the form of two matrices M and N. If you want you can reshape these matrices to vectors by using M = M(:); N = N(:);, but this isn't needed here.
If you were to have yet another variable, you would use: [M, N, P] = ndgrid(0:5:359, 1:5:360, 10:5:1000).
By the way: The code part where you delete the entry [0,0,0] doesn't do anything here, because this value doesn't appear. I see you only needed it, because you were allocating a lot more memory than you actually needed. Here are two versions of your original code, that are not as good as the ndgrid version, but preferable to your original one:
m = 0:5:359;
n = 1:5:360;
K = zeros(length(m)*length(n), 3);
for i = 1:length(m)
for j = 1:length(n)
nextRow = (i-1)*length(n) + j;
K(nextRow, 1) = cosd(m(i)) + cosd(m(i)+n(j));
K(nextRow, 2) = sind(m(i)) + sind(m(i)+n(j));
K(nextRow, 3) = cosd(m(i)) + sind(m(i)+n(j));
end
end
Or simpler, but a bit slower:
K = [];
for m = 0:5:359
for n = 1:5:360
K(end+1,1:3) = 0;
K(end, 1) = cosd(m)+cosd(m+n);
K(end, 2) = sind(m)+sind(m+n);
K(end, 3) = cosd(m)+sind(m+n);
end
end

Matlab: Argmax and dot product for each row in a matrix

I have 2 matrices = X in R^(n*m) and W in R^(k*m) where k<<n.
Let x_i be the i-th row of X and w_j be the j-th row of W.
I need to find, for each x_i what is the j that maximizes <w_j,x_i>
I can't see a way around iterating over all the rows in X, but it there a way to find the maximum dot product without iterating every time over all of W?
A naive implementation would be:
n = 100;
m = 50;
k = 10;
X = rand(n,m);
W = rand(k,m);
Y = zeros(n, 1);
for i = 1 : n
max_ind = 1;
max_val = dot(W(1,:), X(i,:));
for j = 2 : k
cur_val = dot(W(j,:),X(i,:));
if cur_val > max_val
max_val = cur_val;
max_ind = j;
end
end
Y(i,:) = max_ind;
end
Dot product is essentially matrix multiplication:
[~, Y] = max(W*X');
bsxfun based approach to speed-up things for you -
[~,Y] = max(sum(bsxfun(#times,X,permute(W,[3 2 1])),2),[],3)
On my system, using your dataset I am getting a 100x+ speedup with this.
One can think of two more "closeby" approaches, but they don't seem to give any huge improvement over the earlier one -
[~,Y] = max(squeeze(sum(bsxfun(#times,X,permute(W,[3 2 1])),2)),[],2)
and
[~,Y] = max(squeeze(sum(bsxfun(#times,X',permute(W,[2 3 1]))))')

How to write a generalized code

I write a code for linear feedback shift register.My code is in below:
X=5712;
D1(1)=0;
D2(1)=0;
D3(1)=0;
D4(1)=0;
D5(1)=0;
D6(1)=1;
for i=1:X-1
D6(i+1)=D1(i);
D5(i+1)=xor(D1(i),D6(i));
D4(i+1)=D5(i);
D3(i+1)=D4(i);
D2(i+1)=D3(i);
D1(i+1)=D2(i);
end
In my code i can only use 6 shift register.I know for degree,n=2,3,4,6,7,15,22, the polynomial is x^n+x+1.As the polynomial is same for those degrees so i want to write a common code for all.
Matlab experts Please need your help.
Your problem is that you are making separate vectors for each register. Rather make a single matrix (i.e. D replaces all of your D1, D2, ..., Dn) so that you can loop:
X = 20;
n = 6;
D = zeros(X, n);
D(1,n) = 1;
for ii = 1:X-1
D(ii+1, 1:n-2) = D(ii, 2:n-1);
D(ii+1, n-1) = xor(D(ii,1), D(ii,n));
D(ii+1, n) = D(ii, 1);
end
E = D(:, end:-1:1)

Matlab loop over variables (beginner)

I would like to apply a function to several variables. Is there a nice way to do this?
Like:
M = ones(2,2)
N = zeros(3,3)
M = M + 1
N = N + 1
Works but I would like do something of the sort:
M = ones(2,2)
N = zeros(3,3)
L = ?UnknownStructure?(M, N)
for i = 1:length(L)
L(i) = L(i) + 1
end
Or is there a better way entirely to apply a function to a set of variables?
You can use cells:
M = ones(2,2)
N = zeros(3,3)
L = {M, N};
funct=#(x) x+1;
L2=cellfun(funct, L, 'UniformOutput',false);
There is no such thing as references in Matlab, in a sense that you can have two different variable names pointing to the same matrix.
However, you can have an array of matrices.
L = { M, N };
for i = 1:length(L)
L{i} = L{i} + 1
end
I tested this code in Octave. However note: The source matrices M, N are unchanged by this.
Try:
a = ones(2,2)
arrayfun(#(x) 2*x , a)
You can make the function (2*x) whatever you want.