How to solve a linear system of equations with 2D matrices on the RHS - matlab

I am trying to solve this problem:
I am trying to declare a matrix of matrices for the right hand side (RHS), but I do not know how do it. I am trying this:
MatrizResultados = [[1, 3; -1, 2]; [0, 4; 1, -1]; [2, 1; -1, 1]]
But the result is all one matrix, like so:
MatrizResultados =
1 3
-1 2
0 4
1 -1
2 1
-1 1
How can I store these as separate matrices, within one matrix, to solve the above problem?
Here is my current Matlab code, to try and solve this question:
syms X Y Z;
MatrizCoeficientes = [-1, 1, 2; -1, 2, 3; 1, 4, 2];
MatrizVariables = [X; Y; Z];
MatrizResultados = [[1, 3; -1, 2]; [0, 4; 1, -1]; [2, 1; -1, 1]];

The symbolic math toolbox is overkill for this.
This is 4 separate systems of equations, since addition is linear i.e. there is no cross over in matrix elements. You have, for example
- x(1,1) + y(1,1) + 2*z(1,1) = 1
- x(1,1) + 2*y(1,1) + 3*z(1,1) = 0
x(1,1) + 4*y(1,1) + 2*z(1,1) = 2
This can be solved using the mldivide (\) operator, from a matrix of coefficients. This can be constructed like so:
% Coefficients of all 4 systems
coefs = [-1 1 2; -1 2 3; 1 4 2];
% RHS of the equation, stored with each eqn in a row, each element in a column
solns = [ [1; 0; 2], [-1; 1; -1], [3; 4; 1], [2; -1; 1] ];
% set up output array
xyz = zeros(3, 4);
% Loop through solving the system
for ii = 1:4
% Use mldivide (\) to get solution to system
xyz(:,ii) = coefs\solns(:,ii);
end
Result:
% xyz is a 3x4 matrix, rows are [x;y;z],
% columns correspond to elements of RHS matrices as detailed below
xyz(:,1) % >> [-10 7 -8], solution for position (1,1)
xyz(:,2) % >> [ 15 -10 12], solution for position (2,1)
xyz(:,3) % >> [ -1 0 1], solution for position (1,2)
xyz(:,4) % >> [-23 15 -18], solution for position (2,2)

Related

Matlab - How to perform operations on each row between two matrices?

I have two matrices each of which contains two vectors (each row is a vector):
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
I want to calculate two angles between the vectors of the corresponding rows in the matrices (angle between [1 0 0] , [1 1 0] and angle between [2 0 0] , [2 2 0]). In this example, both angles will be 45 degrees. So what I want is a new matrix like this:
angles = [45; 45]
When I try this:
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
dp = u(:,1) .* v(:,1) + u(:,2) .* v(:,2) + u(:,3) .* v(:,3);
angles = atan2d(norm(cross(u,v)),dp)
The anwser will be:
angles = [76.3670 ; 45.8683]
and when I try this (change norm to normr):
u = [1 0 0; 2 0 0]
v = [1 1 0; 2 2 0]
dp = u(:,1) .* v(:,1) + u(:,2) .* v(:,2) + u(:,3) .* v(:,3);
angles = atan2d(norm(crossr(u,v)),dp)
The anwser will be:
angles = [0 0 45.0000 ; 0 0 14.0362]
How can I make it calculate the angle between the vectors of each row?
Try:
u=[1 0 0;2 0 0];
v = [1 1 0;2 2 0];
atan2(cross(u,v,2),dot(u,v,2)) % radians
atan2d(cross(u,v,2),dot(u,v,2)) % degrees
The ,2 in the cross and dot functions specifies the dimension to operate, since you are storing each vector in a row.
There a discussion here, with many other ways to calculate, and you may find one more suitable to your particular case of application.

Reordering rows of several arrays in Matlab

Consider three matrices X1, X2, X3 in Matlab of dimension Nx(N-1) listing some integers among 0,1,...,10.
I want to reorder the elements in each row of X1, X2, X3 wrto X1, then X2 (if some elements of X1 are equal), then X3 (if some elements of X2 are equal) in ascending order.
Example 1
N=3;
X1=[3 8;
7 7;
2 1];
X2=[10 1;
10 9;
4 4];
X3=[1 1;
1 0;
1 0];
%I want to obtain
X1new=[3 8;
7 7;
1 2];
X2new=[10 1;
9 10;
4 4];
X3new=[1 1;
0 1;
0 1];
Example 2
N=4;
X1=[3 8 9;
7 6 6;
2 1 4;
4 4 4];
X2=[10 1 2;
9 10 10;
4 4 5;
5 5 2];
X3=[1 1 1;
0 0 1;
1 0 0;
0 0 0];
%I want to obtain
X1new=[3 8 9;
6 6 7;
1 2 4;
4 4 4];
X2new=[10 1 2;
10 10 9;
4 4 5;
2 5 5];
X3new=[1 1 1;
0 1 0;
0 1 0;
0 0 0];
This code does what I want. Could you suggest more efficient alternatives (if any) for cases in which size(Y,1) is large?
% 1) Create a 3d matrix Y of dimension Nx(N-1)x3
Y=NaN(N,N-1,3);
Y(:,:,1)=X1;
Y(:,:,2)=X2;
Y(:,:,3)=X3;
% 2) Reorder elements in each row (independently)
%wrto Y(:,:,1), then Y(:,:,2), then Y(:,:,3) in ascending order.
%Store everything in Ynew of dimension Nx(N-1)x3
Ynew = NaN(N,N-1,3);
for h = 1:size(Y,1),
Ynew (h,:,:) = sortrows(squeeze(Y(h,:,:)), [1 2 3]);
end
% 3) Create X1new, X2new, X3new
X1new=Ynew(:,:,1);
X2new=Ynew(:,:,2);
X3new=Ynew(:,:,3);
Since the numbers are between 0 and 10, you can easily combine the three matrices into one for the purposes of sorting (step 1); sort each row of the combined matrix and get the indices of that sorting (step 2); and from that build a linear index (step 3) which you can use into the original matrices (step 4):
M = 11; % Strict upper bound on possible values
Y = X1 + X2/M + X3/M^2; % STEP 1: combined matrix
[~, cols] = sort(Y, 2); % STEP 2: sort each row and get indices of sorting
ind = bsxfun(#plus, (1:size(X1,1)).', (cols-1)*size(X1,1)); % STEP 3: linear index
X1new = X1(ind); % STEP 4: result
X2new = X2(ind);
X3new = X3(ind);
sort(X,2) will do this. The 2 is to do it row-wise.
It can be done simply by using
'sort' command in Matlab
X1new = sort(X1,2);
X2new = sort(X2,2);
X3new = sort(X3,2);

Design a simple matrix to group values from matrices

This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.

Find the minimum positive difference between elements in vector

A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
I would like to create a vector C which returns the rownumber of the element in vector A with the smallest non-negative difference to each element in vector B.
So, given the example above, it should return:
C = [1 2 2 3 3 4 4 4]
I'm sure there are many ways to do this. Here's one:
A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
%create matrices of the values to subtract
[a,b] = meshgrid(A,B);
%subtract
aLessB = a-b;
%make sure we don't use the negative values
aLessB(aLessB < 0) = Inf;
%sort the subtracted matrix
[dum, idx] = sort(aLessB, 2, 'ascend');
idx(:,1) is the solution you are looking for.
An alternative solution:
D = bsxfun(#minus, A', B);
D(D < 0) = Inf;
[~, C] = min(D, [], 1);

Changing multiple elements (of known coordinates) of a matrix without a for loop

I have a matrix say
Z = [1 2 3;
4 5 6;
7 8 9]
I have to change its values, say at positions (2,2) and (3,1), to some specified value. I have two matrices rowNos and colNos which contain these positions:
rowNos = [2, 3]
colNos = [2, 1]
Let's say I want to change the value of elements at these positions to 0.
How can I do it without using for loop?
Use sub2ind, it'll convert your sub-indices to linear indices, which is a number pointing at one exact spot in the matrix (more info).
Z = [ 1 2 3 ; 4 5 6 ; 7 8 9];
rowNos = [2, 3];
colNos = [2, 1];
lin_idcs = sub2ind(size(Z), rowNos, colNos)
If you want to operate on all elements on a specific row and column (elements in higher dimensions that is), you can also address them using linear indexing. It only becomes a bit trickier of calculating them:
Z = reshape(1:4*4*3,[4 4 3]);
rowNos = [2, 3];
colNos = [2, 1];
siz = size(Z);
lin_idcs = sub2ind(siz, rowNos, colNos,ones(size(rowNos))); % just the first element of the remaining dimensions
lin_idcs_all = bsxfun(#plus,lin_idcs',prod(siz(1:2))*(0:prod(siz(3:end))-1)); % all of them
lin_idcs_all = lin_idcs_all(:);
Z(lin_idcs_all) = 0;
experiment a bit with sub2ind, and go through my code step-by-step to understand it.
It would've been easier if it was the first dimension you wanted to take all elements off, then you could have used the colon operator :
Z = reshape(1:3*4*4,[3 4 4]);
rowNos = [2, 3];
colNos = [2, 1];
siz = size(Z);
lin_idcs = sub2ind(siz(2:end),rowNos,colNos);
Z(:,lin_idcs) = 0;
Use sub2ind with multiple entries for rows and columns
Z(sub2ind(size(Z), rowNos, colNos))=0
Example:
Z = [1 2 3;
4 5 6;
7 8 9];
rowNos = [2, 3];
colNos = [2, 1];
Z(sub2ind(size(Z), rowNos, colNos))=0
Z =
1 2 3
4 0 6
0 8 9
You would like to do this
z(rowNos, colNos)
but you can not - MATLAB does a Cartesian product of the indices. You can do this trick
idx=(colNos-1)*size(z, 1)+rowNos;
z(idx)=0
Flatten the z-matrix and access it through a linear index, which is a combination of rowNos and colNos. Remember that MATLAB flattens the matrix by columns (column-based matrix storage).