Consider the example from the book Robust control and filtering of singular systems (Please see attached image example). I'm trying to reproduce the same example using Matlab. The problem is when I'm using the svd function I got the matrices N and M which does not satisfy the property
MAN equals to the diagonal of A and one. So to specify the soloution among all the possible SVD decompositions.
Thank you.
Example in the book:
A=[-10 5 6.5
2 -5.5 -1.25
-9 4 8.5];
E=[1 1 0.5
-0.5 1.5 1.75
1 1 0.5]; M=[2 -1 1
1 0.5 -1.5
2 -1 0];
N=[0 1 1
-1 1 1.5
-1 1 -2].
Here is my Matlab code which permits to find matrices M and N such that M[I 0 0;0 I 0;0 0 0]N=E but it does not guarantee the second statement "inv(M)Ainv(N)=[A_bar 0;0 I]"
n=3;
[M,I2,N] = svd(E);
E1=rref([I2 inv(M)]);
I2= E1(:,1:n); % the reduced row echelon form of c
M= inv(E1(:,n+1:end)); % now we have T
N=N';
Related
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)
I have a “for loop” with 1000 iterations, where its output is a 2*2 matrix. So, my question is that “how can I store the output of all iteration as a diagonal (or block diagonal) matrix?”
X_t=[0 0.0016 0 0 -0.0015 0;0 0.0005 0 0 -0.0010 0];
X=[0 2 0 0 -1 0;0 0.5 0 0 -0.01 0];
ar = linspace(1e-3,1e2,1000);
w = 1i*ar;
M = zeros(2*numel(w));
for k=1:numel(w)
P=[(10*exp(-w(k)))/(12*w(k)+1) (-8*exp(-3*w(k)))/(7*w(k)+1);
(5*exp(-8*w(k)))/(9*w(k)+1) (-17*exp(-4*w(k)))/(12*w(k)+1)];
W=[1 0;1/w(k) 0;w(k)/(1+0.3*w(k)) 0;0 1;0 1/w(k);0 w(k)/(1+0.3*w(k))];
Z=eye(2)+(X*W)*P;
Y=((1.4)^2)*eye(2);
Z_t=eye(2)+(X_t*W)*P;
index = 2*k + [-1 0];
M(index, index)=(Z'*Z_t)-(Y'*Y);
end
You should determine which indexes you want to change in each iteration:
index = 2*k + [-1 0];
M(index, index)=(Z'*Z_t)-(Y'*Y);
And to improve the performance, you should preallocate the output matrix:
M = zeros(2*numel(w));
Note that it may be more (memory) efficient to use a sparse matrix.
You can check if your matrix is correctly build using the spy command, which graphically displays the non zero matrix entries:
I want to make a triadiagonal matrix with matlab, using
full(gallery('tridiag', 10, 1, -4, 6, -4, 1))
and i take that i have too many arguments in the function. Is there another way to do this?
I am trying to make the following matrix:
6 -4 1 0 0
-4 6 -4 1 0
1 -4 6 -4 1
0 1 -4 6 -4
0 0 1 -4 6
Since your matrix is pentadiagonal, I think the best solution is to use spdiags:
>> n = 5;
>> full(spdiags(ones(n,1)*[1,-4,6,-4,1],[-2,-1,0,1,2],n,n));
ans =
6 -4 1 0 0
-4 6 -4 1 0
1 -4 6 -4 1
0 1 -4 6 -4
0 0 1 -4 6
The full is optional and not recommended for large n.
Since there are 5 non-zero diagonals this is not a tridiagonal matrix so you cannot use the tridiag option. You have to manually generate such matrix by means of the diag() function, which allows you to create a matrix with a given diagonal and you can as well select which diagonal you want to write.
You can achieve this therefore by creating 5 different matrices, each of them will have a given non-zero diagonal:
n=5;
B=diag(6*ones(n,1),0)+diag(-4*ones(n-1,1),1)+diag(-4*ones(n-1,1),-1)+diag(1*ones(n-2,1),2)+diag(1*ones(n-2,1),-2);
In this code n=5 is the order of your matrix, then diag(6*ones(n,1),0) will create a vector (length n) with all 6 and such vector will be placed in the 0-th diagonal. Such matrix will have zero elsewhere.
Similarly diag(-4*ones(n-1,1),1) will create a vector (length n-1) with all -4 and such vector will be placed in the 1st superdiagonal. Such matrix will have zero elsewhere and we sum such matrix to the previous one.
And such "chain reaction" goes on until the matrix is fully generated.
Update: I've been looking around the gallery() help and there is indeed an option for a Toeplitz pentadiagonal. You might want to use then
full(gallery('toeppen',5,1,-4,6,-4,1))
I agree that for your huge case a sparse-based solution such as that of Troy Haskin is best. However, it's worth noting that you're precisely constructing a Toeplitz matrix (as Alessiox hinted), and you can use the built-in toeplitz() to do that. All that is needed is to figure out the number of zeros needed for padding the input nonzero elements of the first row and column (this is necessary since toeplitz asserts the size of the matrix to construct from the dimensions of the input vector):
n = 5; %// linear size of result
v = [1,-4,6,-4,1]; %// nonzero diagonal elements symmetrically
mid = ceil(length(v)/2); %// index of diagonal in the input vector
zerosvec = zeros(1,n-mid); %// zeros for padding the rest
colvec = [v(mid:-1:1), zerosvec]; %// first column of the result
rowvec = [v(mid:end), zerosvec]; %// first row of the result
toeplitz(colvec,rowvec) %// toeplitz does the heavy lifting
I have the defination of Truncated gaussian kernel as:
So I confuse which is correct implementation of truncated gaussian kernel. Let see two case and let me know, thank you so much
Case 1:
G_truncated=fspecial('gaussian',round(2*sigma)*2 + 1,sigma); % kernel
Case 2:
G=fspecial('gaussian',round(2*sigma)*2 + 1,sigma); % normal distribution kernel
B = ones(round(2*sigma)*2 + 1,round(2*sigma)*2 + 1);
G_truncated=G.*B;
G_truncated = G_truncated/sum(G_truncated(:)); %normalized for sum=1
To add on to the previous post, there is a question of how to implement the kernel. You could use fspecial, truncate the kernel so that anything outside of the radius is zero, then renormalize it, but I'm assuming you'll want to do this from first principles.... so let's figure that out then. First, you need to generate a spatial map of distances from the centre of the mask. In conjunction, you use this to figure out what the Gaussian values (un-normalized) would be. You filter out those values in the un-normalized mask based on the spatial map of distances, then normalize that. As such, given your standard deviation tau, and your radius rho, you can do this:
%// Find grid of points
[X,Y] = meshgrid(-rho : rho, -rho : rho)
dists = (X.^2 + Y.^2); %// Find distances from the centre (Euclidean distance squared)
gaussVal = exp(-dists / (2*tau*tau)); %// Find unnormalized Gaussian values
%// Filter out those locations that are outside radius and set to 0
gaussVal(dists > rho^2) = 0;
%// Now normalize
gaussMask = gaussVal / (sum(gaussVal(:)));
Here is an example with using rho = 2 and tau = 2 with the outputs at each stage:
Stage #1 - Find grid co-ordinates
>> X
X =
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
-2 -1 0 1 2
>> Y
Y =
-2 -2 -2 -2 -2
-1 -1 -1 -1 -1
0 0 0 0 0
1 1 1 1 1
2 2 2 2 2
Step #2 - Find distances from centre and unnormalized Gaussian values
>> dists
dists =
8 5 4 5 8
5 2 1 2 5
4 1 0 1 4
5 2 1 2 5
8 5 4 5 8
>> gaussVal
gaussVal =
0.3679 0.5353 0.6065 0.5353 0.3679
0.5353 0.7788 0.8825 0.7788 0.5353
0.6065 0.8825 1.0000 0.8825 0.6065
0.5353 0.7788 0.8825 0.7788 0.5353
0.3679 0.5353 0.6065 0.5353 0.3679
Step #3 - Filter out locations that don't belong within the radius and set to 0
>> gaussVal =
0 0 0.6065 0 0
0 0.7788 0.8825 0.7788 0
0.6065 0.8825 1.0000 0.8825 0.6065
0 0.7788 0.8825 0.7788 0
0 0 0.6065 0 0
Step #4 - Normalize so sum is equal to 1
>> gaussMask =
0 0 0.0602 0 0
0 0.0773 0.0876 0.0773 0
0.0602 0.0876 0.0993 0.0876 0.0602
0 0.0773 0.0876 0.0773 0
0 0 0.0602 0 0
To verify that the mask sums to 1, just do sum(gaussMask(:)) and you'll see it's equal to 1... more or less :)
Your definition of truncated gaussian kernel is different than how MATLAB truncates filter kernels, though it generally won't matter in practice for sizable d.
fspecial already returns truncated AND normalized filter, so the second case is redundant, because it generates exactly the same result as case 1.
From MATLAB help:
H = fspecial('gaussian',HSIZE,SIGMA) returns a rotationally
symmetric Gaussian lowpass filter of size HSIZE with standard
deviation SIGMA (positive). HSIZE can be a vector specifying the
number of rows and columns in H or a scalar, in which case H is a
square matrix.
The default HSIZE is [3 3], the default SIGMA is 0.5.
You can use fspecial('gaussian',1,sigma) to generate a 1x1 filter and see that it is indeed normalized.
To generate a filter kernel that fits your definition, you need to make B in your second case a matrix that has ones in a circular area. A less strict (but nonetheless redundant in practice) solution is to use fspecial('disk',size) to truncate your gaussian kernel. Don't forget to normalize it in either case.
The answer of rayryeng is very useful for me. I only extend the gaussian kernel to ball kernel. The ball kernel is defined :
So based on answer of rayryeng. We can do it by
sigma=2;
rho=sigma;
tau=sigma;
%// Find grid of points
[X,Y] = meshgrid(-rho : rho, -rho : rho)
dists = (X.^2 + Y.^2); %// Find distances from the centre (Euclidean distance squared)
ballVal=dists;
ballVal(dists>sigma)=0;
ballVal(dists<=sigma)=1;
%// Now normalize
ballMask = ballVal / (sum(ballVal(:)));
Let me know, if it has any error or problem. Thank you
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