I've been set a question asking me to solve a system of linear equations. In the question it states I should set up a matrix A and column vector b to solve the equation Ax=b, where x is the column vector (w x y z).
A = [1 1 1 1; 0 1 4 -2; 2 0 -2 1; 1 -2 -1 1]
b = [28;7;22;-4]
A1 = inv(A).*b
sum(A1,2)
This is what I've done so far, however I know the answer that MATLAB gives me is incorrect, as the right solutions should be w=10.5, x=9, y=2.5, z=6.
Can someone point me in the right direction/ show me where I'm going wrong? (I'm fairly new to MATLAB so very unsure about it all).
Thanks.
A = [1 1 1 1; 0 1 4 -2; 2 0 -2 1; 1 -2 -1 1];
b = [28;7;22;-4];
A1 = A \ b;
ans = sum(A1,2);
For a reference concerning the \ operator, please read this: https://it.mathworks.com/help/matlab/ref/mldivide.html
The correct code to use your technique would be:
A1 = inv(A) * b;
but as you may notice, the Matlab code analyzer will point out that:
For solving a system of linear equations, the inverse of a
matrix is primarily of theoretical value. Never use the inverse of a
matrix to solve a linear system Ax=b with x=inv(A)*b, because it is
slow and inaccurate.
Replace inv(A)*b with A\b
Replace b*inv(A) with b/A
and that:
INV(A)*b can be slower than A\b
Related
a = [1 2 3
2 4 6
3 6 9];
b = pinv(a);
[U,S,V] = svd(a);
T = S;
T(find(S~=0)) = 1./S(find(S~=0));
svda = V * T' * U';
I find that the pinv method in Matlab uses the SVD decomposition to calculate pseudo-inverse, so I tried to solve the matrix a.
And as shown above, theoretically the b should be equal with svda, but the Matlab result said they are totally different. Why?
b is
0.00510204081632653 0.0102040816326531 0.0153061224489796
0.0102040816326531 0.0204081632653061 0.0306122448979592
0.0153061224489796 0.0306122448979592 0.0459183673469388
svda is
-2.25000000000000 -5.69876639328585e+15 3.79917759552390e+15
-2.14021397132170e+15 1.33712246709292e+16 -8.20074512351222e+15
1.42680931421447e+15 -7.01456098285751e+15 4.20077088383351e+15
How does pinv get to its result?
REASON:
Thanks to Cris, I check my S, and it do have 2 very large number, and that is the source of this strange result.
S:
14.0000000000000 0 0
0 1.00758232556386e-15 0
0 0 5.23113446604828e-17
By pinv method and Cris method, this 2 latter numbers should set to 0 which I didnt do. So here is the reason。
pinv doesn't just invert all the non-zero values of S, it also removes all the nearly zero values first. From the documentation:
pinv(A,TOL) treats all singular values of A that are less than TOL as zero. By default, TOL = max(size(A)) * eps(norm(A)).
pinv more or less does this:
[U,S,V] = svd(a);
I = find(abs(S) > max(size(a)) * eps(norm(a)));
T = zeros(size(S));
T(I) = 1 ./ S(I);
svda = V * T.' * U';
On my machine, isequal(svda,b) is true, which is a bit of a coincidence because the operations we're doing here are not exactly the same as those done by pinv, and you could expect rounding errors to be different. You can see what pinv does exactly by typing edit pinv in MATLAB. It's a pretty short function.
Note that I used T.', not T'. The former is the transpose, the latter is the complex conjugate transpose (Hermitian transpose). We're dealing with real-valued matrices here, so it doesn't make a difference in this case, but it's important to use the right operator.
I am running into issues when attempting to shift a Hessian to be positive definite for an optimization problem in Matlab. An example of my problem is:
H=[1 2 2;
2 3 2;
1 3 1];
[V,D]=eig(H);
While H*V-V*D, as it should, essentially equals zero:
V*D*V' does not provide the original H matrix
I actually tried to run your code:
H = [
1 2 2;
2 3 2;
1 3 1
];
[V,D] = eig(H);
test = norm(H*V-V*D,inf) / norm(V*D,inf);
and I'm seeing no obvious problems with the example you posted. The eigenvalues and vectors that I get satisfy their defining equation with high accuracy:
test = 7.57596318689868e-16
On the top of that, as #kpg987 pointed out, you have to use the inverse of V, not the transposed version of V. And if you perform the following test:
test = V * D * inv(V);
You will obtain your original hessian (or something very very close to it).
Suppose that I have the solution vector
conv=(y0,y1,y0+y1,y0+y1+y2,y0+y1+y2+y3);
where y0,y1,y2,y3,y4 are symbolic variables and y2=y0+y1, y3=y0+y1+y2, y4=y0+y1+y2+y3. Now, I assign the values y0=1,y1=1, and then I would like to evaluate recursively (with a for) the solution. Is it possible?
I could solve the problem making
y0=1;
y1=1;
y2=eval(conv(3));
conv(3)=y2;
y3=eval(conv(4));
conv(4)=y3;
y4=eval(conv(5));
conv(5)=y4;
But this is not with a for. It is not the best solution (I know it)
I hope that anyone can help me because the real problem is with 130 variables.
Regards
You need to define your variables as symbolic. Then you can simply use solve:
syms y0 y1 y2 y3 y4
eq = [y0==sym(0),
y1==sym(1),
y2==y0+y1,
y3==y0+y1+y2,
y4==y0+y1+y2+y3]
s = solve(eq)
s.y2
s.y3
s.y4
which returns 1, 2, and 4, respectively.
This system can also be solved numerically using linear algebra with mldivide:
A = [1 0 0 0 0;
0 1 0 0 0;
1 1 -1 0 0;
1 1 1 -1 0;
1 1 1 1 -1];
b = [0;1;0;0;0];
y = A\b
If A and/or b is symbolic, a symbolic linear system solver will be used.
Thanks much for your time and for all your help.
Actually, I made a mistake in the previous post when specifying the problem. Thus, I reformulate my question using a simpler example. I need to solve symbolically the equation Ct = Z/(P-I) or Ct*(P-I) = Z.
I already know the answer => Ct = [sigma, 1-sigma]
How to program "correctly" the code in order to get the solution
syms sigma;
Ct = sym('Ct',[1 2]);
%
P = [sigma 1-sigma;
sigma 1-sigma];
I = [1 0;
0 1];
Z = [0 0];
%
solve(Ct*(P-I) == Z);
So far, I get :
Z =
0 0
Warning: The solutions are parametrized by the symbols:
z = C_
In solve at 190
In test_matrix_sigma at 13
Or with
solve(Ct == Z/(P-I), Ct);
I get:
Warning: System is rank deficient. Solution is not unique.
Warning: 4 equations in 2 variables.
In /opt/MATLAB/R2013a/toolbox/symbolic/symbolic/symengine.p>symengine at 56
In mupadengine.mupadengine>mupadengine.evalin at 97
In mupadengine.mupadengine>mupadengine.feval at 150
In solve at 170
In test_matrix_sigma at 13
---------------------------------------------------------------------------------------
Thanks for the answer !
Now I have two issues:
1) When I try to handla a more complicated system:
syms a b P1 P2;
I = [1 0 0 0;
0 1 0 0;
0 0 1 0;
0 0 0 1];
%
P = [a*P1 (1-a)*P1 (1-b)*(1-P1) b*(1-P1);
a*P1 (1-a)*P1 (1-b)*(1-P1) b*(1-P1);
b*(1-P2) (1-b)*(1-P2) (1-b)*P2 b*(1-P2);
b*(1-P2) (1-b)*(1-P2) (1-b)*P2 b*(1-P2)];
%
assume(a, 'real');
assume(b, 'real');
assume(P1, 'real');
assume(P2, 'real');
%
answer = null((P-I)');
disp(answer);
I get
ans =
[ empty sym ]
as the only answer.
2) If there is a way in maltlab to "solve" the above symbolic matrix P and find the symbolic determinant ?
For instance, if I do eid(P) it works;
when I do det(P) it gives 0 as answer...
This post is an answer to a different problem, that was first asked by the OP before being edited. I leave the problem and solution here in case someone ever runs into the same problem:
I need to solve symbolically the following matrix equation to find out Ct (a vector ???):
syms a b P1 P2
%
P = [a*P1 (1-a)*P1 (1-b)*(1-P1) b*(1-P1);
a*P1 (1-a)*P1 (1-b)*(1-P1) b*(1-P1);
b*(1-P2) (1-b)*(1-P2) (1-b)*P2 b*(1-P2);
b*(1-P2) (1-b)*(1-P2) (1-b)*P2 b*(1-P2)];
%
solve(Ct*(P-1) == 0, Ct);
How to proceed ?
So far I get:
Undefined function or variable 'Ct'.
Error in matrix_test (line 10) solve(Ct*(P-1) == 0, Ct);
The error you get is because you did not assign Ct before trying to solve for your equation. In the equation Ct*(P-1) == 0, Matlab does not know what Ct is. You could remedy this by creating a symbolic vector (see sym documentation). For instance:
Ct = sym('Ct', [1 4]);
However, using solve on this would not give you the solutions you're looking for: instead, Matlab is going to give you the trivial answer Ct = 0, which of course is a correct answer to your equation.
What you really want to find is the null space of the (P-1)' matrix: the null space is the set of vectors X such that (P-1)'X = 0 (Which is the same thing as X'(P-1) = 0, so Ct = X'). The Matlab function null (see doc) is what you need. Using your code, I get:
null((P-1)')
ans =
[ -1, 0]
[ 1, 0]
[ 0, -1]
[ 0, 1]
This means that any linear combination of the vectors [-1, 1, 0, 0] and [0, 0, -1, 1] belong to the null space of (P-1)', and therefore its transpose is the Ct you were looking for.
N.B.: This result is easily confirmed by observation of your initial matrix P.
This edited problem is only slightly different from the first one. Once again, you are looking to solve an homogeneous system of linear equations.
The warnings you get simply warn you of that: there are an infinity of solutions ; The first warning tells you that the answer is parameterized by C_ (meaning it's in the complex plane, you could add assume(sigma, 'real') and assume(Ct, 'real') if you wanted, you'd get an answer parameterized by R_.
The solution is to find the null space of the matrix (P-I)', as for the previous problem.
null((P-I)')
ans =
-sigma/(sigma - 1)
1
Now if your vector Z became different from 0, you would need to add the particular solution, that is Z/(P-I). In the present case, it gives:
Z/(P-I)
Warning: System is rank deficient. Solution is not unique.
ans =
[ 0, 0]
This means that in this case the particular solution is [0 0], and the result of null gives you the homogeneous solution. Remember that the complete solution of a linear system of equations is the sum of the particular solution + a linear combination of the elements of the null space. A way to express this in Matlab could be:
syms lambda real;
sol = Z/(P-I) + lambda * null((P-I)')'
sol =
[ -(lambda*sigma)/(sigma - 1), lambda]
I am trying to write a Matlab program that accepts variables for a system from the user, but there are more variables than system parameters. To be specific, six variables in three equations:
w - d - M = 0
l - d - T = 0
N - T + M = 0
This could be represented in matrix form as A*x=0 where
A = [1 0 0 -1 0 -1;
0 1 0 -1 -1 0;
0 0 1 0 -1 1];
x = [w l N d T M]';
I would like to be able to solve this system given a known subset of the variables. For example, if the user gives d, T, M, then the system is trivially solved for the other three variables. If the user supplies w, N, M, then it becomes a solvable 3-DOF system. And so on. (If the user over- or under-specifies the system then an error may of course result.)
Given any one of these combinations it's simple to (a priori) use matrix algebra to calculate the unknown quantities. But I don't know how to solve the general case, aside from using the symbolic toolbox (which I prefer not to do for compatibility reasons).
When I started with this approach I thought this step would be easy, but my linear algebra is rusty; am I missing something simple?
First, let x be a vector with NaN for the unknown values. This allows you to use ISNAN to find the indeces of the unknowns. If you calculate A*x for only the user-specified terms, that gives you a column of constants b. Take those constants to the right-hand side of the equation, and you have an equation of the form A*x = -b.
A = [1 0 0 -1 0 -1;
0 1 0 -1 -1 0;
0 0 1 0 -1 1];
idx = ~isnan(x);
b = A(:,idx)*x(idx); % user provided constants
z = A(:,~idx)\(-b); % solution of Ax = -b
x(~idx) = z;
With input x = [NaN NaN NaN 1 1 1]', for instance, you get the result [2 2 0 1 1 1]'. This uses MLDIVIDE, I'm not well versed enough in linear algebra to know whether PINV or something else would be better.
Given the linear system
A = [1 0 0 -1 0 -1;
0 1 0 -1 -1 0;
0 0 1 0 -1 1];
A*x = 0
Where the elements of x are identified as:
x = [w l N d T M]';
Now, suppose that {d,T,M} have known, fixed values. What we need are the indices of these elements in x. We've chosen the 4th, 5th and 6th elements of x to be knowns.
known_idx = [4 5 6];
unknown_idx = setdiff(1:6,known_idx);
Now, let me pick some arbitrary numbers for those known variables.
xknown = [1; -3; 7.5];
We will partition A into two submatrices, corresponding to the known and unknown variables.
Aknown = A(:,known_idx);
Aunknown = A(:,unknown_idx);
Now, move the known values to the right hand side of the equality, and solve. See that Aknown is a 3x3 matrix, so the problem is (hopefully) well posed.
xunknown = Aunknown\(-Aknown*xknown)
xunknown =
-8.5
2
10.5
Combine it all into the final solution.
x = zeros(6,1);
x(known_idx) = xknown;
x(unknown_idx) = xunknown;
x =
-8.5
2
10.5
1
-3
7.5
Note that I've expanded this all out into a few lines to show what is happening more clearly. But I could have done it all in just a line or two of code had I wanted to be parsimonious.
Finally, see that had I chosen some other sets of numbers to be the knowns, such as {l,d,T}, then the resulting system would be singular. So you must watch for that event. A test on the rank of Aunknown might be useful to weed out the problems. Or you might choose to employ pinv to build the solution.
The system of equations is fixed? What if you store the variables present in your three equations in a list per equation:
(w, d, M)
(l, d, T)
(N, T, M)
Then you get the user input and you can calculate the number of variables given in each equation:
User input: w, N, M
Given variables:
(w, d, M) -> 2
(l, d, T) -> 0
(N, T, M) -> 1
This would trivially give you d from the first equation. Therefore you end up with two equations containing two variables and you know you the equation system you have to solve.
It's basically your own simple symbolic solver for a single system of equations.