Generalized Eigenvalue problem for degenerate matrices AND Jordan form - matlab

I'm looking for a way to combine two eigenvalue decomposition methods implemented in Matlab. The first method implements the generalized eigenvalue problem, and can be used as follows:
[Gamma, Lambda] = eig(M1, M2);
If matrix M2 is not degenerate, this method returns the same answer as eig(M2^(-1) * M1), but I need to use this generalized form, because M2 may be degenerate.
I also have the problem that the returned matrix of eigenvectors is degenerate, so to get the eigenvalue decomposition, I need to use the Jordan form. If matrix M2 were not degenerate, I could use:
[Gamma, Lambda] = jordan(M2 \ M1)
But this does not work, because M2 is degenerate.
Is there any way to combine these two methods, so I could solve the problem of eigenvalue decomposition for the case where M2 and Gamma are both degenerate?
UPD: Minimal reproducible example:
M1 = [2 -1 0; 1 0 0; 0 0 0]; M2 = [0 0 0; 0 2 -1; 0 1 0];
[Gamma, Lambda] = eig(M1, M2)
Gamma =
0 1 0
0 0 0
-1 0 1
Lambda =
0 0 0
0 Inf 0
0 0 0
In this example, I'm ok that some eigenvalues are infinite, but I need a non-degenerate Gamma.

Related

How to reduce coefficients to their lowest possible integers using Matlab - Balancing Chemical Equations

I am attempting to develop a Matlab program to balance chemical equations. I am able to balance them via solving a system of linear equations. Currently my output is a column vector with the coefficients.
My problem is that I need to return the smallest integer values of these coefficients. For example, if [10, 20, 30] was returned. I want [1, 2, 3] to be returned.
What is the best way to accomplish this?
I want this program to be fully autonomous once it is fed a matrix with the linear system. Thus I can not play around with the values, I need to automate this from the code. Thanks!
% Chemical Equation in Matrix Form
Chem = [1 0 0 -1 0 0 0; 1 0 1 0 0 -3 0; 0 2 0 0 -1 0 0; 0 10 0 0 0 -1 0; 0 35 4 -4 0 12 1; 0 0 2 -1 -3 0 2]
%set x4 = 1 then Chem(:, 4) = b and
b = Chem(:, 4); % Arbitrarily set x4 = 1 and set its column equal to b
Chem(:,4) = [] % Delete the x4 column from Chem and shift over
g = 1; % Initialize variable for LCM
x = Chem\b % This is equivalent to the reduced row echelon form of
% Chem | b
% Below is my sad attempt at factoring the values, I divide by the smallest decimal to raise all the values to numbers greater than or equal to 1
for n = 1:numel(x)
g = x(n)*g
M = -min(abs(x))
y = x./M
end
I want code that will take some vector with coefficients, and return an equivalent coefficient vector with the lowest possible integer coefficients. Thanks!
I was able to find a solution without using integer programming. I converted the non-integer values to rational expressions, and used a built-in matlab function to extract the denominator of each of these expressions. I then used a built in matlab function to find the least common multiples of these values. Finally, I multiplied the least common multiple by the matrix to find my answer coefficients.
% Chemical Equation in Matrix Form
clear, clc
% Enter chemical equation as a linear system in matrix form as Chem
Chem = [1 0 0 -1 0 0 0; 1 0 1 0 0 -3 0; 0 2 0 0 -1 0 0; 0 10 0 0 0 -1 0; 0 35 4 -4 0 -12 -1; 0 0 2 -1 -3 0 -2];
% row reduce the system
C = rref(Chem);
% parametrize the system by setting the last variable xend (e.g. x7) = 1
x = [C(:,end);1];
% extract numerator and denominator from the rational expressions of these
% values
[N,D] = rat(x);
% take the least common multiple of the first pair, set this to the
% variable least
least = lcm(D(1),D(2));
% loop through taking the lcm of the previous values with the next value
% through x
for n = 3:numel(x)
least = lcm(least,D(n));
end
% give answer as column vector with the coefficients (now factored to their
% lowest possible integers
coeff = abs(least.*x)

How can I create a modified identity matrix?

I have an identity matrix in MATLAB which is used in some regression analysis for joint hypothesis tests. However, when I change the linear restrictions for my tests, I can no longer rely on the identity matrix.
To give a simple example, here is some code which produces an identity matrix depending on the value of y:
for i = [1, 2, 4]
y = i
x = 5;
H = eye(y*x)
end
However, what I need is not the identity matrix, but the first two rows and all others to be zero.
For the first example, the code produces an eye(5):
H =
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
I need something that given y does not produce the identity but in fact produces:
H =
1 0 0 0 0
0 1 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
Can I adjust the identity matrix to include zeroes only after the first two rows?
I think the simplest solution is to make a matrix of all zeroes and then just place the two ones by linear indexing:
H = zeros(x*y);
H([1 x*y+2]) = 1;
Generalizing the above to putting the first N ones along the diagonal:
H = zeros(x*y);
H(x*y.*(0:(N-1))+(1:N)) = 1;
As suggested in this comment you can use diag:
diag([ones(2,1); zeros(x*y-2,1)])
This works because diag makes a vector become the main diagonal of a square matrix, so you can simply feed it the diagonal vector, which is your case would be 2 1s and the rest 0s.
Of course if you need a variable amount of 1s, which I was in doubt about hence the comment,
n=2;
diag([ones(n,1); zeros(x*y-n,1)])
Here are some alternatives:
Use blkdiag to diagonally concatenate an identity matrix and a zero matrix:
y = 5; x = 2;
H = blkdiag(eye(x), zeros(y-x));
A more exotic approach is to use element-wise comparisons with singleton expansion and exploit the fact that two NaN's are not equal to each other:
y = 5; x = 2;
H = [1:x NaN(1,y-x)];
H = double(bsxfun(#eq, H, H.'))

Matlab Not Returning Orthonormal Matrix of Eigenvectors

When I try to find the eigen-decomposition of a matrix in Matlab that has a repeated eigenvalue but is NOT defective, it is not returning an orthonormal matrix of eignevectors. For example:
k = 5;
repeats = 1;
% First generate a random matrix of eignevectors that is orthonormal
V = orth(rand(k));
% Now generate a vector of eigenvalues with the given number of repeats
D = rand(k,1);
for i = 1:repeats
% Put one random value into another (note this sometimes will result in
% less than the given number of repeats if we ever input the same
% number)
D(ceil(k*rand())) = D(ceil(k*rand()));
end
A = V'*diag(D)*V;
% Now test the eignevector matrix of A
[V_A, D_A] = eig(A);
disp(V_A*V_A' - eye(k))
I am finding that my matrix of eigenvectors V_A is not orthogonal i.e. V_A*V_A' is not equalling the identity matrix (taking into account rounding errors).
I was under the impression that if my matrix was real and symmetric then Matlab would return an orthogonal matrix of eigenvectors, so what is the issue here?
This seems to be a numerical precision issue.
The eigenvectors of a real symmetric matrix are orthogonal. But your input matrix A is not exactly symmetric. The differences are on the order of eps, as expected from numerical errors.
>> A-A.'
ans =
1.0e-16 *
0 -0.2082 -0.2776 0 0.1388
0.2082 0 0 -0.1388 0
0.2776 0 0 -0.2776 0
0 0.1388 0.2776 0 -0.5551
-0.1388 0 0 0.5551 0
If you force A to be exactly symmetric you'll get an orthogonal V_A, up to numerical errrors on the order of eps:
>> A = (A+A.')/2;
>> A-A.'
ans =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
>> [V_A, D_A] = eig(A);
>> disp(V_A*V_A' - eye(k))
1.0e-15 *
-0.3331 0.2220 0.0755 0.1804 0
0.2220 -0.2220 0.0572 -0.1665 0.1110
0.0755 0.0572 -0.8882 -0.0590 -0.0763
0.1804 -0.1665 -0.0590 0 -0.0555
0 0.1110 -0.0763 -0.0555 0
Still, it's surprising that so wildly different results are obtained for V_A when A is symmetric and when A is nearly symmetric. This is my bet as to what's happening: as noted by #ArturoMagidin,
(1) Eigenvectors corresponding to distinct eigenvalues of a symmetric matrix must be orthogonal to each other. Eigenvectors corresponding to the same eigenvalue need not be orthogonal to each other.
(2) However, since every subspace has an orthonormal basis,you can find orthonormal bases for each eigenspace, so you can find an orthonormal basis of eigenvectors.
Matlab is probably taking route (2) (thus forcing V_a to be orthogonal) only if A is symmetric. For A not exactly symmetric it probably takes route (1) and gives you a basis of each subspace, but not necessarily with orthogonal vectors.
The eigenvectors of a real matrix will be orthogonal if and only if AA'=A'A and eigenvalues are distinct. If eigenvalues are not distinct, MATLAB chooses an orthogonal system of vectors. In the above example, AA'~=A'A. Besides, you have to consider round off and numerical errors.

problem in finding eigenvectors of a matrix in MATLAB

I have a symmetric matrix with the elements A=[8.8191,0,1.0261; 0,3,0; 1.0261,0,3.1809];
I used the eig(A) function in MATLAB , the eigenvalues and eigenvectors are given :
eigvect =
0.1736 0 0.9848
0 -1.0000 0
-0.9848 0 0.1736
eigval =
3.0000 0 0
0 3.0000 0
0 0 9.0000
Eigenvalues are correct but the eigenvectors are not which I expect, because I think 2 of them should be equal. Does MATLAB calculate correctly the eigenvectors?
The definition of an eigenvalue can be found anywhere on the web
A*v = lam*v
v being the eigenvector with lam, its corresponding eigenvalue.
So test your results:
i =1;
A*eigvect (:,i)-eigval(i,i)*eigvect(:,i) %which should be approx [0;0;0]
It is not necessary that each of the repeating eigenvalue should have its (independent) associated eigenvector. This means, an nxn matrix with an eigenvalue repeating more than once has less or equal to n linearly independent eigenvectors.
Example 1: Matrix
2 0;
0 2
has eigenvalue 2 (repeating twice), but it has two linearly independent eigenvectors associated with eigenvalue 2
Example 2:Matrix
A= 1 1 1 -2;
0 1 0 -1;
0 0 1 1;
0 0 0 1
has eigenvalue 1 (repeating four times), but it has only two independent eigenvectors associated with eigenvalue 1.

Linear programming - MATLAB

I've a [8x4] matrix, 'A', and a [8x1] matrix, 'B'. How do I check if there exists a [4x1] matrix 'x' such that A * X = B?
This can be done using linprog in MATLAB, but I'm not sure how to give the constraints. I tried x = linprog([],[],[],A,B);, but this doesn't seem to work.
How to specify the condition x>=0 and optimize it for A*X-B so that, if it returns 0, we know there is X.
Update:
pinv in MATLAB doesn't work in all the cases. Consider the following example:
A= [1 0 0 0
0 1 -1 -1
-1 -1 1 -1
-1 -1 -1 1
0 0 0 0
0 0 0 0
0 0 0 0
1 1 1 1]
B = [0
0
0
-1
0
0
0
1]
using pinv gives the the value of X as:
X = [-2.7756e-017
0.5000
0.5000
0]
but when linear programming is used I get x as:
X = [ 0
0.5000
0.5000
0]
This is the reason why I preferred linprog tool in MATLAB. I just used it the way I mentioned previously but it is throwing a lot of warnings. I still think there is a better way to use this function correctly. It did not throw for this matrix but in general when I loop through a lot of matrices my command window overflow with warnings.
Why use linear programming? You can just solve the system A*x=B directly:
A =[ 1 -1 -1 -1 1 0 0 1
-1 1 -1 0 0 1 0 0
-1 -1 1 0 1 0 0 0
-1 -1 -1 1 1 1 0 0]'; %'#
B = [-1 -1 0 0 0 0 1 1]'; %'#
x = A\B
x =
0.16327
0.097959
0.46531
0.11837
The problem you may face is that A can be rank deficient, but in that case, you'll get infinitely many solutions for x.
But why use a code that will do MORE work than necessary to solve the problem? Just use the pseudo-inverse. If A is of full rank, then backslash will be entirely sufficient.
Compute the solution. If the norm of your residuals is less than some tolerance, then you have a solution. Note that essentially no solution is ever assured to give you truly zero residuals, so you must apply a tolerance. Thus
x = A\B;
if norm(B - A*x) < tol
disp('Eureeka!')
end
Or use x=pinv(A)*B if you are worried about the rank of A.
Trying to throw linprog at the problem will surely not be more efficient than the direct solution itself.
Edit: Since non-negativity of the result has now been added as a requirement, use lsqnonneg instead. Just compare the norm of the residual vector to a tolerance. If the norm is too large, then no solution exists.
Unfortunately, you can not use array division. This is not the same a matrix division. However, you could use the inverse of the Matrix A to multiply it with matrix B to get x x = (A-1)B, but I am not sure if an inverse is possible for non-square matrix A (8x4). Hence, you might not have been able to work that with linprog