Solve a system of equations with a constraint to x in Matlab - matlab

I have given a nxn upper triangular matrix R and I want to solve the system of equations Rx=0 where x is a vector of size n. Moreover the lowermost diagonalement of R is 0 (R(n,n)=0). Therefore I want to set x(n)=1.
I tried some loops but I do not know how to solve it.
Thank you for your help.

It's guaranteed that R has a zero eigenvalue, and the solution you want is a multiple of the eigenvector corresponding to that eigenvalue. Let's create some matrix R first:
>> R = triu(rand(3, 3));
>> R(3, 3) = 0;
>> R
R =
0.8147 0.9134 0.2785
0 0.6324 0.5469
0 0 0
Now let's get the eigenvalues and eigenvectors:
>> [V, E] = eig(R)
V =
1.0000 -0.9806 0.4289
0 0.1958 -0.5909
0 0 0.6833
E =
0.8147 0 0
0 0.6324 0
0 0 0
The eigenvectors are the diagonal elements of E
>> E = diag(E);
>> index = find(abs(E) < 1e-16); %// NB don't use find(E==0) because of fp problems...
Now pull out the correct eigenvector
>> v = V(:, index);
and make sure its final element is equal to 1
>> v = v / v(end)
v =
0.6277
-0.8648
1.0000
You can check that this is the solution you want
>> R * v
ans =
0
0
0

Related

Is there a way to group matrix elements in matlab?

I am working on a problem which requires me to group array elements and average each group. For example consider the 4 x 4 matrix M,
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
I want to group this into a 2 x 2 matrix, taking an average of the elements so we would get
M1 = [0.5 0.75;
0.5 0.5;]
does anyone know a way to do this?
Many thanks
You can do this using conv2, and a little indexing, like so:
>> A = conv2(M,ones(2), 'same');
>> A(1:2:end,1:2:end)/4
ans =
0.5000 0.7500
0.5000 0.5000
I think the way to go is to first split your matrix in parts using mat2cell, then apply your functions to each part and merge them to a new matrix:
>> M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;]
M =
1 0 0 1
1 0 1 1
1 1 0 1
0 0 0 1
>> T=mat2cell(M, [2 2], [2 2])
T =
2×2 cell array
{2×2 double} {2×2 double}
{2×2 double} {2×2 double}
>> M1 = cellfun(#mean, cellfun(#mean, T, 'UniformOutput', false))
M1 =
0.5000 0.7500
0.5000 0.5000
>>
You can do something like this for any rectangle, where x and y denote the size of domains that you want to average.
function M1 = get_means(M, x, y)
[rows, cols] = size(M);
if mod(rows, x) == 0 && mod(cols, y) == 0
for i = 1:y:cols
for j = 1:x:rows
M1((j+x-1)/x, (i+y-1)/y) = sum(M(j:j+x-1,i:i+y-1),'all')/(x*y);
end
end
else
error('The matrix doesn''t have compatible dimensions.')
end
end
You can loop over the grouped matrices and then calculate the mean
M = [ 1 0 0 1;
1 0 1 1;
1 1 0 1;
0 0 0 1;];
n=2; % 2x2 mat
% create new matrix with means
MM = zeros(n,n);
% row counter for mean-Matrix
r=1;
% loop over matrix groups
for row=1:n:size(M,1)
c = 1; % column counter for mean-Matrix
for col=1:n:size(M,2)
MM(r,c) = mean(mean(M(row:row+n-1, col:col+n-1)));
c = c+1;
end
r = r+1;
end
Output:
MM =
0.5000 0.7500
0.5000 0.5000

Null space calculation for same matrix with different data type inconsistent

I'm running the following code to find the eigenvector corresponding to eigenvalue of 1 (to find the rotation axis of an arbitrary 3x3 rotation matrix).
I was debugging something with the identity rotation, but I'm getting two different answers.
R1 =
1.0000 -0.0000 0.0000
0.0000 1.0000 0.0000
-0.0000 0 1.0000
R2 =
1 0 0
0 1 0
0 0 1
Running the null space computation on each matrix.
null(R1 - 1 * eye(3))
>> 3x0 empty double matrix
null(R2 - 1 * eye(3))
>>
1 0 0
0 1 0
0 0 1
Obviously the correct answer is the 3x0 empty double matrix, but why is R2 producing a 3x3 identity matrix when R1 == R2 ?
It makes sense that the nullspace of a zero matrix (rank 0) is an identity matrix, as any vector x in R^3 will produce A*x = 0.
>> null(zeros(3, 3))
ans =
1 0 0
0 1 0
0 0 1
This would be the case of R2 - eye(3) if R2 is exactly eye(3)
It also makes sense that the nullspace of a full rank matrix is an empty matrix, as no vectors different than 0 will produce A*x = 0:
>> null(eye(3))
ans = [](3x0)
which could be the case of R1 - eye(3) if R1 is not exactly eye(3) so the result is rank 3. For example:
>> R1 = eye(3) + 1e-12*diag(ones(3,1))
R1 =
1.0000 0 0
0 1.0000 0
0 0 1.0000
>> null(R1 - 1 * eye(3))
ans = [](3x0)
>> rank(R1 - 1 * eye(3))
ans = 3

How to improve this code for replacing elements of a matrix from another matrices in MATLAB?

So I have these 4 same-sized matrices:
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
And I want to put the elements from each matrix into the diagonal of zero matrix, so it would create something like this:
f = 0.5 2.0 0 0 0 0 0 0
1.7 2.5 0 0 0 0 0 0
0 0 1.0 4.0 0 0 0 0
0 0 3.0 5.0 0 0 0 0
0 0 0 0 1.5 6.0 0 0
0 0 0 0 4.5 7.5 0 0
0 0 0 0 0 0 2.0 8.0
0 0 0 0 0 0 6.0 10.0
This is what I've come up with:
f = zeros(8,8);
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
for i = 1:2:8 %odd index number
for j = 2:2:8 %even index number
f(i,i) = k(1,i)
f(i,j) = l(1,i)
f(j,i) = m(1,i)
f(j,j) = n(i,1)
end;
end;
disp(f)
But the result put the elements not into the diagonal of matrix f=zero(8,8), and I've always got the error of Index exceeds matrix dimensions.
Can I get some pointers on how to fix this code?
I think you intended to write this:
for i = 2:2:8
f(i-1,i-1) = k(i/2)
f(i-1,i) = l(i/2)
f(i,i-1) = m(i/2)
f(i,i) = n(i/2)
end
Though there must be simpler ways to accomplish the same thing. For example, check out the function blkdiag!
If you're looking for compact, then here's an interesting solution using eye, repelem, and logical indexing:
>> f = zeros(8);
>> f(repelem(eye(4, 'logical'), 2, 2)) = [k m l n].';
f =
0.5000 2.0000 0 0 0 0 0 0
1.7000 2.5000 0 0 0 0 0 0
0 0 1.0000 4.0000 0 0 0 0
0 0 3.0000 5.0000 0 0 0 0
0 0 0 0 1.5000 6.0000 0 0
0 0 0 0 4.5000 7.5000 0 0
0 0 0 0 0 0 2.0000 8.0000
0 0 0 0 0 0 6.0000 10.0000
Cris Luengo's answer is more flexible and read much better than what I have here, but this is something you probably want to learn if you will do a lot of work using MATLAB.
(This method generally performs better because it removes the need of a for loop.)
k = [0.5;1.0;1.5;2.0];
l = [2;4;6;8];
m = [1.7;3.0;4.5;6.0];
n = [2.5;5.0;7.5;10.0];
f = zeros(8); % to create a square matrix, you only need to specify the size with one value
f(1:18:end) = k;
f(9:18:end) = l;
f(2:18:end) = m;
f(10:18:end) = n;
Here, f is used as if it is a vector (array) even though it is a 8*8 matrix. In Matlab, you can access a single element from a matrix by either specifying the row and column number or linear indexing.
More details can be found here: https://uk.mathworks.com/help/matlab/math/matrix-indexing.html (see Linear Indexing)
Another option is to construct the diagonal, and the two off-diagonal vectors first and then use diag to create the matrices and then adding them together.
%Data
k = [0.5;1.0;1.5;2.0];
l = [2;4;6;8];
m = [1.7;3.0;4.5;6.0];
n = [2.5;5.0;7.5;10.0];
%Construct vectors
diagonal = [1;0].*k.' + [0;1].*n.'; %Diagonal of the matrix
offu = [1;0].*l'; %Upper diagonal
offl = [1;0].*m'; %Lower diagonal
A = diag(diagonal(:)) + diag(offu(1:end-1),1) + diag(offl(1:end-1),-1);
I have no idea whether it is faster than the other answers, but I like its transparency of what is happening.
NOTE: In order to construct the variables diagonal, offu and offl I am using implicit expansion which requires Matlab R2016b or newer. If you are using an older version, you can instead use bsxfun.
A sorry, I missed the everything is shifted. My former answer was completely incorrect...
I still would go for something with blkdiag, you just need to redistribute your matrices:
k = [0.5; 1.0; 1.5; 2.0];
l = [2; 4; 6; 8];
m = [1.7; 3.0; 4.5; 6.0];
n = [2.5; 5.0; 7.5; 10.0];
Y = arrayfun(#(i) [k(i), l(i); m(i), n(i)], 1:4, 'UniformOutput', false);
blkdiag(Y{:})
X = cat(3, [k, m], [l, n]);
blkdiag(squeeze(X(1,:,:)), squeeze(X(2,:,:)), squeeze(X(3,:,:)), squeeze(X(4,:,:)))

Creating multidimensional sequences in MATLAB [duplicate]

My question seems wierd, because I know that we can't use a matrix as input in linspace(x1,x2,n) function. But my question is more something like : I have a vector A=linspace(0,Amax,N), and I want to build a serie of vector B_k or big matrix B_k=linspace(0,A(k),N) but without making a for loop that slows down my whole calculation.
% already defined A
rGC=linspace(0,75e-7,N);
for k=1:N
r=rGC(k);
v=linspace(0,A*r,N);
y=f(r,v);
INT=trapz(v,y);
% The same for 8 more integrals
end
Maybe something using interp1, to interpolate something like:
[0 0 0 ... 0 ]
[A(1) A(2) A(3) ... A(N)]
with N rows .... For instance:
N = 5;
Amax = 15;
A = linspace(0, Amax, N);
x = [0 1];
y = zeros(2, N);
y(2, :) = A;
B = interp1(x, y, linspace(0, 1, N))
Which will give:
B =
0 0 0 0 0
0 0.9375 1.8750 2.8125 3.7500
0 1.8750 3.7500 5.6250 7.5000
0 2.8125 5.6250 8.4375 11.2500
0 3.7500 7.5000 11.2500 15.0000
Not sure it will be any faster than a for loop or that even get the point here :)

Linspace using matrix input matlab

My question seems wierd, because I know that we can't use a matrix as input in linspace(x1,x2,n) function. But my question is more something like : I have a vector A=linspace(0,Amax,N), and I want to build a serie of vector B_k or big matrix B_k=linspace(0,A(k),N) but without making a for loop that slows down my whole calculation.
% already defined A
rGC=linspace(0,75e-7,N);
for k=1:N
r=rGC(k);
v=linspace(0,A*r,N);
y=f(r,v);
INT=trapz(v,y);
% The same for 8 more integrals
end
Maybe something using interp1, to interpolate something like:
[0 0 0 ... 0 ]
[A(1) A(2) A(3) ... A(N)]
with N rows .... For instance:
N = 5;
Amax = 15;
A = linspace(0, Amax, N);
x = [0 1];
y = zeros(2, N);
y(2, :) = A;
B = interp1(x, y, linspace(0, 1, N))
Which will give:
B =
0 0 0 0 0
0 0.9375 1.8750 2.8125 3.7500
0 1.8750 3.7500 5.6250 7.5000
0 2.8125 5.6250 8.4375 11.2500
0 3.7500 7.5000 11.2500 15.0000
Not sure it will be any faster than a for loop or that even get the point here :)