Inserting matrix into another matrix with Matlab - matlab

I want to put a small matrix (p-by-q) called B into a bigger matrix (m-by-n) called A. How can I do it? Matrix B should be put on the right corner of matrix A:

You can do this with basic array indexing, for example:
m = 3;
n = 4;
A = rand(m,n)
p = 2;
q = 3;
B = rand(p,q)
A(end-p+1:end,end-q+1:end) = B
... assuming that p <= m and q <= n of course.

Related

MATLAB: efficient generating of block matrices using a block vector

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{:});

Performance of using a matrix as vector index

In my code I have a slow part of which the idea can be summarized in the following short example:
A = randi(10,5); %Random 5×5 matrix containing integers ranging from 0 to 10
B = rand(10,1); %Random 10×1 vector containing values ranging from 0 to 1
C = B(A); %New 5×5 matrix consisting of elements from B, indexed using A
In my case, the matrix A is sized 1000×1000, B is a 500×1 vector and C is also 1000×1000. Given that this 3rd line is in a for loop, where A is constant and B is updated every iteration, how can I further improve speed performance? According to the profile viewer 75% of code execution is at this single line. As expected, using a for loop for this operation is much slower (10x for a 1000×1000 matrix):
AA = A(:); %Convert matrix to vector
for k=1:length(AA) %Loop through this vector and use it as index
D(k) = B(AA(k));
end
E = reshape(D,5,5); %Reshape vector to matrix of 5x5
Any ideas to optimize this?
Edit: Script used to measure performance:
N = 1500;
A = randi(500,N);
AA = A(:);
D = zeros(N,N);
B = rand(500,1);
f1 = #() VectorIndex(A,B);
timeit(f1,1)
f2 = #() LoopIndex(AA,B,N);
timeit(f2,1)
function C = VectorIndex(A,B)
C = B(A);
end
function D = LoopIndex(AA,B,N)
D = zeros(N,N);
for k=1:length(AA)
D(k) = B(AA(k));
end
D = reshape(D,N,N);
end

matlab vectorization and avoid for loop

There are two matrix X and M and I need to obtain the following matrix D
m = 20; n = 10;
X = rand(m,n);
M = rand(m,m);
M = (M + M')/2;
D = zeros(n,n);
for i = 1:n
for j = 1:n
D(i,j) = X(:,i)'*M*X(:,j);
end
end
When n and m are large, the computation of D is very slow. Is there any way to speed up?
The answer would be:
D = 0.5*X.'*(M+M')*X
(This is a slight modification of the solution provided by Divakar, so that the correct matrix D is returned)

Assigning a matrix as an element of another matrix

Suppose I have the n x m matrices A,B,C. I want to make a "3 x 1" block-matrix Y, such that
Y(1,1) = A, Y(2,1) = B, Y(3,1) = C. Is that possible in MATLAB?
As an alternative to storing the three n x m matrices in a cell vector, consider storing them in a three-dimensional array of size n x m x 3. You can use the cat command to concatenate the matrices along the third dimension, for example:
>> n = 2; m = 3;
>> A = rand(n, m); B = rand(n, m); C = rand(n, m);
>> Y = cat(3, A, B, C)
Y(:,:,1) =
0.792207329559554 0.655740699156587 0.849129305868777
0.959492426392903 0.0357116785741896 0.933993247757551
Y(:,:,2) =
0.678735154857773 0.743132468124916 0.655477890177557
0.757740130578333 0.392227019534168 0.171186687811562
Y(:,:,3) =
0.706046088019609 0.27692298496089 0.0971317812358475
0.0318328463774207 0.0461713906311539 0.823457828327293
This can also be accomplished by indexing, for example:
>> Y(:,:,1) = A; Y(:,:,2) = B; Y(:,:,3) = C;
>> Y
Y(:,:,1) =
0.792207329559554 0.655740699156587 0.849129305868777
0.959492426392903 0.0357116785741896 0.933993247757551
Y(:,:,2) =
0.678735154857773 0.743132468124916 0.655477890177557
0.757740130578333 0.392227019534168 0.171186687811562
Y(:,:,3) =
0.706046088019609 0.27692298496089 0.0971317812358475
0.0318328463774207 0.0461713906311539 0.823457828327293
Yes, this is available using cell arrays.
if you have as stated three matrices A,B,C of size n x m.
to assign them to Y your code should be.
Y{1,1} = A;
Y{2,1} = B;
Y{3,1} = C;
As you see cell arrays use {} instead of ().
For more information about cell arrays visit Matlab help

Replace the diagonal of matrix

I am interesting to replace the diagonal of matrix D to 1,2,3,4.
This is matrix D:
A=[1,2,3,4,2,3,4,5; 3,4,5,6,4,5,6,7];
D=[A;A];
D=[D D]; % size of matrix [4x16] %
To set the main diagonal to integers starting a 1 and incrementing by 1:
D(eye(4)==1) = 1:4
Or to generalize it:
n = min(size(D));
D(eye(n)==1) = 1:n;
note here that the ==1 is to convert the output of eye(n), the identity matrix, to type logical.
EDIT:
This is just a guess at what you mean by all the diagonals but here goes:
n = size(D,1);
m = size(D,2);
I = repmat(eye(min([n,m])), ceil(n/m), ceil(m/n));
I = I(1:n, 1:m)==1
d = repmat(1:min([n,m]), 1, max([ceil(n/m), ceil(m/n)]));
d = d(1:max(m,n));
D(I) = d