2D matrix of matrices - matlab

I have two diagonal matrices. I am trying to build a larger block diagonal matrix from them. For example if I had this:
D = diag(zeros(3,1)+1)
D =
1 0 0
0 1 0
0 0 1
and...
E = diag(zeros(2,1)+2, -1) + diag(zeros(2,1)+2, +1) + diag(zeros(3,1)+4)
E =
4 2 0
2 4 2
0 2 4
I have an equation that says A*U = X
Where A is
[E D 0
D E D
0 D E]
This is for 3x3. 5x5 would look like this:
A =
[E D 0 0 0
D E D 0 0
0 D E D 0
0 0 D E D
0 0 0 D E]
A would be another diagonal matrix consisting of these matrices. I need to produce a 40x40 and it would take a VERY LONG TIME to do manually, of course.
How can I define that? I haven't figured out how to use blkdiag to construct.

I solved this on my own manually because I could never find a Matlab function to help me.
for n = 1:Distance_Resolution
A(((n-1)*Distance_Resolution +1):n*Distance_Resolution, ((n-1)*Distance_Resolution +1):n*Distance_Resolution) = A1;
if n == Distance_Resolution
else
A((n*Distance_Resolution+1):(n+1)*(Distance_Resolution), ((n-1)*Distance_Resolution+1:n*Distance_Resolution)) = A2;
A((n-1)*Distance_Resolution+1:n*Distance_Resolution, (n*Distance_Resolution+1):(n+1)*(Distance_Resolution)) = A2;
end
end
This will produce a block matrix that has the above specified demands and is of length Distance_Resolution x Distance_Resolution x Distance_Resolution. I defined A1 and A2 through help from above poster (Fo is just a constant here):
vector = zeros(Distance_Resolution,1) - Fo;
A2 = diag(vector);
A1 = toeplitz([1+4*Fo, -Fo, zeros(1,Distance_Resolution-2)]);
This is a workable code snippet, but I am still looking for a smarter way to code it.

Related

Quadratic Program formulation: Matlab

Given this objective function:
Minimize:
f = (Ax + By)' * G * (Ax + By)
subject to some equalities and inequalities.
where x and y are real-valued vectors (decision variables) with p and q elements, respectively. A of size m * p, B of size m * q, G is a symmetric matrix of size m * m.
My question is how to write f in the form v' * G * v, such that it can be easily be used in quadprog. In other words, how to mix A, B and G?
This looks incompletely specified!
It seems, for whatever reason, you want to model in terms of two variable components. Now you did not specify how they interact with each other.
As most optimizers work on a single variable-vector, you need to concatenate yours.
As you did not show G, i'm assuming you got one G for x and one for y, let's call it H.
(Remark: not a matlab user; don't take example-syntax for granted!)
z = [x y]
P = blkdiag(G,H)
assuming x and y independent in regards to quadratic-term
e.g. no x0*y1 like terms
Solve: for z` P z
Example:
x = [x0 x1 x2]
y = [y0 y1]
G = [6 2 1; 2 5 2; 1 2 4]
H = [8 2; 2 10]
# G
6 2 1
2 5 2
1 2 4
# H
8 2
2 8
z = [x0 x1 x2 y0 y1]
P = [6 2 1 0 0; 2 5 2 0 0; 1 2 4 0 0; 0 0 0 8 2; 0 0 0 2 8]
# P
6 2 1 0 0
2 5 2 0 0
1 2 4 0 0
0 0 0 8 2
0 0 0 2 8

Speedup 3D array multiplication

I have the following code snippet, which multiplies each 2D cross section of a 3D array by a vector:
A = zeros(N,M);
for k = 1:M
B = C(:,:,k);
A(:,k) = B * f(:,k);
end
When I profile the code I see that for N=200, M = 25 this can be quite slow (relative to other parts of my code); in particular the line:
B=C(:,:,k)
can take up a large fraction of the total runtime. Is there some way I could speed this up?
You can use bsxfun combined with permute to perform the required multiplications with singleton expansion, and then add along the appropriate dimension to compute the matrix multiplications.
Define example data:
N = 5;
M = 4;
C = rand(N,N,M);
f = rand(N,M);
Then the result is computed as
result = permute(sum(bsxfun(#times, C, permute(f,[3 1 2])),2), [1 3 2]);
As a check, compare with the result computed using the loop:
A = zeros(N,M);
for k = 1:M
B = C(:,:,k);
A(:,k) = B * f(:,k);
end
result./A
gives
ans =
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

Solving a system of matrix equations using MATLAB?

I have a system of three equations that I'd like to solve via MATLAB, and I'm a bit confused on how to go about doing it.
I have three equations:
A = R*P1
B = R*P2
C = R*P3
A, B, C, and P1, P2, and P3 are 3x1 matrices, while R is a 3x3 matrix. R is the same for all three equations.
I need to find R, and am given A, B, C, and the P's.
I wanted to use fsolve, but it seems that fsolve doesn't work when the variables are matrices. What is an alternative method that you would recommend using?
Just making up some numbers to work with:
P1 = [1;1;1];
P2 = [2;3;4];
P3 = [5;4;3];
R = [2 4 5; 1 5 4; 1 2 3];
Which would mean that:
A = [11;10;6];
B = [36;33;20];
C = [41;37;22];
If A, B, C, P1, P2, P3 are all numerical, why don't you simply use the ldivide or \ operator? This will allow you to solve your linear system directly. I can see that you have the following relationships:
R*P1 = A
R*P2 = B
R*P3 = C
You can see that each matrix equation yields three constraints. What you can do is create one system that encapsulates all matrix equations together thus yielding 9 constraints. As such, you'll need to reformulate this to be able to solve for your coefficients in your matrix R differently. To do this, we need to reshape your matrix R such that it becomes a 9-element vector. In other words, we can then reformulate your system like so:
[P1 0 0 0 0 0 0] [R1] [ ]
[0 0 0 P1 0 0 0] [R2] [ A ]
[0 0 0 0 0 0 P1] [R3] [ ]
[P2 0 0 0 0 0 0] [R4] [ ]
[0 0 0 P2 0 0 0] * [R5] = [ B ]
[0 0 0 0 0 0 P2] [R6] [ ]
[P3 0 0 0 0 0 0] [R7] [ ]
[0 0 0 P3 0 0 0] [R8] [ C ]
[0 0 0 0 0 0 P3] [R9] [ ]
P * R = D
You'll see that we have a 9 x 9 matrix called P, our matrix R which is reshaped into a vector so that we can solve for the coefficients and D are A,B,C concatenated together into one vector. R1 to R9 are the coefficients of the matrix R that are read from left to right and top to bottom.
Therefore, to find your coefficients in your matrix, simply do:
R = P^{-1}*D
As such, simply construct the matrix P and vector D like so:
P = [P1.' zeros(1,6); zeros(1,3) P1.' zeros(1,3); zeros(1,6) P1.'; ...
P2.' zeros(1,6); zeros(1,3) P2.' zeros(1,3); zeros(1,6) P2.'; ...
P3.' zeros(1,6); zeros(1,3) P3.' zeros(1,3); zeros(1,6) P3.'];
D = [A; B; C];
Now, simply solve for R and reshape it back into a 3 x 3 matrix. Therefore:
R = P \ D;
R = reshape(R, 3, 3).';
reshape turns our vector into a 3 x 3 matrix, but it constructs the matrix in column-major format, so you need to transpose the result after you call reshape. With your example, this is what we get. I construct P1, P2, P3, A, B, C, then use the code I had from before:
P1 = [1;1;1];
P2 = [2;3;4];
P3 = [5;4;3];
A = [11;10;6];
B = [36;33;20];
C = [41;37;22];
P = [P1.' zeros(1,6); zeros(1,3) P1.' zeros(1,3); zeros(1,6) P1.'; ...
P2.' zeros(1,6); zeros(1,3) P2.' zeros(1,3); zeros(1,6) P2.'; ...
P3.' zeros(1,6); zeros(1,3) P3.' zeros(1,3); zeros(1,6) P3.'];
D = [A; B; C];
R = P \ D;
R = reshape(R, 3, 3).';
To verify that R is correct, do:
A1 = R*P1;
B1 = R*P2;
C1 = R*P3;
We get for each:
A1 =
11
10
6
B1 =
36
33
20
C1 =
41
37
22
This matches up with your example. However, note that you may get a warning that R is ill-conditioned. This is because you may not have enough constraints to properly find a unique inverse. You may have to add more constraints to get a unique inverse, but if you can't, then use this with caution.
Have you tried to flatten out the matrices inside of the solve function? There is a collect function in MATLAB that collects coefficients, but you need to check if it works with supplying a row matrix, as opposed to a sum. (maybe sum(row matrix) - if it also combines like terms)
Something like:
[x,y,x] = solve(sum(R*P1)==A, sum(R*P2)==B, sum(R*P3)==C, x,y,z)
or the fsolve function

Matlab: Block Tridiagonal with Non-Square Vectors

I'm trying to create a diagonal matrix using the following matrix as the diagonal
base = [a b c d e f 0;
0 g h i j k l];
I need the resulting matrix to look like this...
[a b c d e f 0 0 0;
0 g h i j k l 0 0;
0 0 a b c d e f 0;
0 0 0 g h i j k l];
except it needs to be "n" elements tall
I have tried using the kron function, but it shifts each consecutive row too many elements to the right.
How can I accomplish what I need in a way where I can select n arbitrarily?
You can do it pretty fast with a 2D convolution:
n = 4; %// desired number of rows in result. Should be a multiple of size(base,1)
T = eye(n-1);
T(2:size(base,1):end,:) = 0;
result = conv2(base,T);
Example: with
base =
0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0
0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578
and n=4 the result is
result =
0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0 0 0
0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578 0 0
0 0 0.7497 0.3782 0.4470 0.5118 0.6698 0.3329 0
0 0 0 0.9850 0.5638 0.9895 0.4362 0.4545 0.8578
The easy way is to use repeated out-of-bounds assignment. MATLAB will automatically pad any missing entries with 0 in those cases. Here's how:
%// Some test variables
a = rand; g = rand;
b = rand; h = rand;
c = rand; i = rand;
d = rand; j = rand;
e = rand; k = rand;
f = rand; l = rand;
%// base matrix
base = [
a b c d e f 0;
0 g h i j k l];
%// use out-of-bounds assignment
n = 3;
output = base;
for ii = 1:n
output(end+1:end+size(base,1), size(base,1)*ii+1:end+size(base,1)) = base;
end
The hard way is the faster way (relevant for when n is large and/or you need to repeat this very often). Figure out the pattern behind which indices would be filled in the final matrix by which values in the original matrix, then generate a list of those indices and assign those values to those indices:
[b1,b2] = size(base);
[ii,jj,vv] = find(base);
inds = bsxfun(#plus, (ii + (n+1)*b1*(jj-1)).', (0:n).'*b1*(1 + (n+1)*b1));
output = zeros( (n+1)*b1, b2+n*b1 );
output(inds) = repmat(vv.', n+1, 1)
I'll leave it as an exercise for you to figure out what happens here exactly :)

How to create a rank k matrix using MATLAB?

Im looking to create a matrix of rank k.
The dimension of the matrix is m x n. The input k satisfies that condition that k < min(m,n).
It's not really so clear what you are aiming for.
But in order to create a matrix B with specific rank k, from a matrix A (with rank at least k), you may like to utilize svd and proceed like:
>>> A= rand(7, 5);
>>> rank(A)
ans = 5
>>> [U, S, V]= svd(A);
>>> k= 3;
>>> B= U(:, 1: k)* S(1: k, 1: k)* V(:, 1: k)';
>>> rank(B)
ans = 3
Well, a trivial method is to produce a matrix that looks like:
1 0 0 0 0
0 1 0 0 0
0 0 1 1 1
0 0 0 0 0
i.e. k columns of the identity matrix, then repeat the last column n-k times (or m-k times, depending on orientation).
A matrix of rank 1 can be created by the outer product of two vectors, for example:
A = randn(10,1) * randn(1,10);
Add together k of these and you will have a matrix of rank k. Like this:
>> A = zeros(10);
>> for i = 1:4, A = A + randn(10,1) * randn(1,10); end
>> rank(A)
ans = 4