I want to solve linear Programming by MATLAB . For this purpose , I am following the following link . Linear Programming .
Here , a sample problem is given :
Find x that minimizes
f(x) = –5x1 – 4x2 –6x3,
subject to
x1 – x2 + x3 ≤ 20
3x1 + 2x2 + 4x3 ≤ 42
3x1 + 2x2 ≤ 30
0 ≤ x1, 0 ≤ x2, 0 ≤ x3.
First, enter the coefficients
f = [-5; -4; -6];
A = [1 -1 1
3 2 4
3 2 0];
b = [20; 42; 30];
lb = zeros(3,1);
Next, call a linear programming routine.
[x,fval,exitflag,output,lambda] = linprog(f,A,b,[],[],lb);
My question is that what is meant by this line ?
lb = zeros(3,1);
Without this line , all problems solvable by MATLAB is seen as infeasible . Can you help me in this purpose ?
This is not common to ALL linear problems. Here you deal with a problem where there are some constraints on the minimal values of the solution:
0 ≤ x1, 0 ≤ x2, 0 ≤ x3
You have to set up these constraints in the parameters of your problem. The way to do so is by specifying lower boundaries of the solution, which is the 5th argument.
Without this line, the domain on which you search for a solution is not bounded, and exitflag has the value -3 after calling the function, which is precisely the error code for unbounded problems.
Related
I want to use solve() to solve a large system of linear equations. The solve() function needs equations and variables. I use a loop to generate the equations and my variables are contained in a large array. This is a simple code of what I am trying to do:
x = sym('x',[1 3])
eqn = sym('eqn', [1,3])
eqn1 = 2*x1 + x2 + x3 - 2 == 0
eqn2 = 2*x2 -x2 -x1- x3 == 3
eqn3 = 2*x2+ x1 + 3*x3 == -10
Y = solve(eqn, x)
MATLAB does not recognize my variable x1. I have solved the same system using the following code:
syms x1 x2 x3
eqn1 = 2*x1 + x2 + x3 == 2
eqn2 = 2*x2 -x2 -x1 - x3 == 3
eqn3 = 2*x2+ x1 + 3*x3 == -10
X = solve([eqn1, eqn2, eqn3, eqn4], [x1 x2 x3])
structfun(#subs,X)
But this is useless for a very large number of equations. What am I doing wrong?
You don't need symbolic (syms) for that. This is a standard linear system of equations that can be represented as:
Ax = b where A = [2 1 1; -1 1 -1; 1 2 3], x = [x1; x2; x3] and b = [0; 3; -10]
To solve for x, you would first define
A = [2 1 1; -1 1 -1; 1 2 3]
and
b = [0; 3; -10]
and then solve using
x = A\b
PS. There are some odd things in your question, eg. in eq.2 eqn2 = 2*x2 -x2 -x1- x3 == 3 I assume you omitted simplying this to -x1 +x2 -x3 ==3.
PS2. This is pretty standard Matlab, you can find a lot of info under the standard mldivide page in the documentation along with a lot similar questions here on SO.
Suppose I have a fmincon function. As we know from matlab documentation we can impose linear and nonlinear constraints.
Suppose now I have a function of 3 parameters to optimize.
And I want 3 of them to be greater than 0 and 1 of them to be greater than -1 I would need 4 constraints but I get an error.
Simple example (working code):
A=eye(4)
A(4,4)=-1;
b=100*ones(4,1)
b(4,1)=+1
fun = #(x)100*(x(2)-x(1)^2)^2 + (1-x(1))^2+x(3);
fmincon(fun,[0,0,0],A,b)
The error is
Error using fmincon (line 287)
A must have 3 column(s).
It is strange that A can only have n constraints (that you could add with non linear)
Thanks
Your function fun expects exactly three inputs, i.e. the vector x will always be 3x1. So your starting point must be a 3x1 vector, not 4x1. The fmincon function allows you to specify any number of linear constraints of the form Ax ≤ b. Here, the Ax is a matrix multiplication: each column in A corresponds to one of the dimensions of x, thus A has to have exactly three columns. The number of rows can be any arbitrary number - though of course b will have to have the same dimension!
Small example: if you have the inequality 3*x + 4*y - z ≤ 1, then the first row of A is [3, 4, -1]. And the first entry of b is 1. Now, let's make up an additional constraint, e.g. y ≤ 4, so you have to add a row [0, 1, 0] to A and 4 to b. Your matrices are
A = [3, 4, -1;
0, 1, 0];
b = [1; 4];
In your case, you want more conditions than variables. You can do that by calling eye with two parameters: number of rows and number of columns:
>> A = eye(4, 3);
A =
1 0 0
0 1 0
0 0 1
0 0 0
and manually add the last constraint:
A(4,:) = [0, 0, -1];
To implement the constraint, that all parameters have to be greater than 0, and z has to be smaller than 1, you can create your matrices as follows:
A = -eye(4, 3);
A(4,:) = [0, 0, 1];
b = [zeros(3,1); 1];
i.e. the equations are:
-1 * x ≤ 0, which equals x ≥ 0
-1 * y ≤ 0, which equals y ≥ 0
-1 * z ≤ 0, which equals z ≥ 0
z ≤ 1
now, you can use fmincon:
>>fmincon(fun, zeros(3,1), A, b);
ans =
1.0000
1.0000
0.0000
Instead of treating the the two absolute constraints as 4 separate linear constrains why not treat them as a 2 nonlinear constrains specifically. x^2 < 9 ?
How can I calculate in MatLab similarity transformation between 4 points in 3D?
I can calculate transform matrix from
T*X = Xp,
but it will give me affine matrix due to small errors in points coordinates. How can I fit that matrix to similarity one? I need something like fitgeotrans, but in 3D
Thanks
If I am interpreting your question correctly, you seek to find all coefficients in a 3D transformation matrix that will best warp one point to another. All you really have to do is put this problem into a linear system and solve. Recall that warping one point to another in 3D is simply:
A*s = t
s = (x,y,z) is the source point, t = (x',y',z') is the target point and A would be the 3 x 3 transformation matrix that is formatted such that:
A = [a00 a01 a02]
[a10 a11 a12]
[a20 a21 a22]
Writing out the actual system of equations of A*s = t, we get:
a00*x + a01*y + a02*z = x'
a10*x + a11*y + a12*z = y'
a20*x + a21*y + a22*z = z'
The coefficients in A are what we need to solve for. Re-writing this in matrix form, we get:
[x y z 0 0 0 0 0 0] [a00] [x']
[0 0 0 x y z 0 0 0] * [a01] = [y']
[0 0 0 0 0 0 x y z] [a02] [z']
[a10]
[a11]
[a12]
[a20]
[a21]
[a22]
Given that you have four points, you would simply concatenate rows of the matrix on the left side and the vector on the right
[x1 y1 z1 0 0 0 0 0 0] [a00] [x1']
[0 0 0 x1 y1 z1 0 0 0] [a01] [y1']
[0 0 0 0 0 0 x1 y1 z1] [a02] [z1']
[x2 y2 z2 0 0 0 0 0 0] [a10] [x2']
[0 0 0 x2 y2 z2 0 0 0] [a11] [y2']
[0 0 0 0 0 0 x2 y2 z2] [a12] [z2']
[x3 y3 z3 0 0 0 0 0 0] * [a20] = [x3']
[0 0 0 x3 y3 z3 0 0 0] [a21] [y3']
[0 0 0 0 0 0 x3 y3 z3] [a22] [z3']
[x4 y4 z4 0 0 0 0 0 0] [x4']
[0 0 0 x4 y4 z4 0 0 0] [y4']
[0 0 0 0 0 0 x4 y4 z4] [z4']
S * a = T
S would now be a matrix that contains your four source points in the format shown above, a is now a vector of the transformation coefficients in the matrix you want to solve (ordered in row-major format), and T would be a vector of target points in the format shown above.
To solve for the parameters, you simply have to use the mldivide operator or \ in MATLAB, which will compute the least squares estimate for you. Therefore:
a = S^{-1} * T
As such, simply build your matrix like above, then use the \ operator to solve for your transformation parameters in your matrix. When you're done, reshape T into a 3 x 3 matrix. Therefore:
S = ... ; %// Enter in your source points here like above
T = ... ; %// Enter in your target points in a right hand side vector like above
a = S \ T;
similarity_matrix = reshape(a, 3, 3).';
With regards to your error in small perturbations of each of the co-ordinates, the more points you have the better. Using 4 will certainly give you a solution, but it isn't enough to mitigate any errors in my opinion.
Minor Note: This (more or less) is what fitgeotrans does under the hood. It computes the best homography given a bunch of source and target points, and determines this using least squares.
Hope this answered your question!
The answer by #rayryeng is correct, given that you have a set of up to 3 points in a 3-dimensional space. If you need to transform m points in n-dimensional space (m>n), then you first need to add m-n coordinates to these m points such that they exist in m-dimensional space (i.e. the a matrix in #rayryeng becomes a square matrix)... Then the procedure described by #rayryeng will give you the exact transformation of points, you then just need to select only the coordinates of the transformed points in the original n-dimensional space.
As an example, say you want to transform the points:
(2 -2 2) -> (-3 5 -4)
(2 3 0) -> (3 4 4)
(-4 -2 5) -> (-4 -1 -2)
(-3 4 1) -> (4 0 5)
(5 -4 0) -> (-3 -2 -3)
Notice that you have m=5 points which are n=3-dimensional. So you need to add coordinates to these points such that they are n=m=5-dimensional, and then apply the procedure described by #rayryeng.
I have implemented a function that does that (find it below). You just need to organize the points such that each of the source-points is a column in a matrix u, and each of the target points is a column in a matrix v. The matrices u and v are going to be, thus, 3 by 5 each.
WARNING:
the matrix A in the function may require A LOT of memory for moderately many points nP, because it has nP^4 elements.
To overcome this, for square matrices u and v, you can simply use T=v*inv(u) or T=v/u in MATLAB notation.
The code may run very slowly...
In MATLAB:
u = [2 2 -4 -3 5;-2 3 -2 4 -4;2 0 5 1 0]; % setting the set of source points
v = [-3 3 -4 4 -3;5 4 -1 0 -2;-4 4 -2 5 -3]; % setting the set of target points
T = findLinearTransformation(u,v); % calculating the transformation
You can verify that T is correct by:
I = eye(5);
uu = [u;I((3+1):5,1:5)]; % filling-up the matrix of source points so that you have 5-d points
w = T*uu; % calculating target points
w = w(1:3,1:5); % recovering the 3-d points
w - v % w should match v ... notice that the error between w and v is really small
The function that calculates the transformation matrix:
function [T,A] = findLinearTransformation(u,v)
% finds a matrix T (nP X nP) such that T * u(:,i) = v(:,i)
% u(:,i) and v(:,i) are n-dim col vectors; the amount of col vectors in u and v must match (and are equal to nP)
%
if any(size(u) ~= size(v))
error('findLinearTransform:u','u and v must be the same shape and size n-dim vectors');
end
[n,nP] = size(u); % n -> dimensionality; nP -> number of points to be transformed
if nP > n % if the number of points to be transform exceeds the dimensionality of points
I = eye(nP);
u = [u;I((n+1):nP,1:nP)]; % then fill up the points to be transformed with the identity matrix
v = [v;I((n+1):nP,1:nP)]; % as well as the transformed points
[n,nP] = size(u);
end
A = zeros(nP*n,n*n);
for k = 1:nP
for i = ((k-1)*n+1):(k*n)
A(i,mod((((i-1)*n+1):(i*n))-1,n*n) + 1) = u(:,k)';
end
end
v = v(:);
T = reshape(A\v, n, n).';
end
I have a cell type variable with 12 columns and 20000 rows. I call it Atotal:
Atotal= [ATY1;ATY2;ATY3;ATY4;ATY5;ATY6;ATY7;ATY8;ATY9;ATY10;ATY11;ATY12;ATY13;ATY14;ATY15;ATY16;ATY17];
Atotal={ 972 1 0 0 0 0 0 21 60 118 60110 2001
973 0 0 1 0 0 0 15 46 1496 60110 2001
980 0 0 0 0 1 0 4 68 142 40502 2001
994 1 0 0 0 0 0 13 33 86 81101 2001
995 0 0 0 1 0 0 9 55 183 31201 2001
1024 1 0 0 0 0 0 10 26 3 80803 2001}
I get my dependent and independent variables from there:
Y1=cell2mat(Atotal(:,2));
X1=cell2mat(Atotal(:,3));
And then I regress them. Considering that my dependent variable Y1 is binary and my independent variable X1 is also a categorical variable, I use the follwoing code, still not sure if it is the correct one.
mdl1 = fitlm(X1,Y1,'CategoricalVars',logical([1]));
Then I add more dummies and try the same code:
X2=cell2mat(Atotal(:,4));
X3=cell2mat(Atotal(:,5));
X4=cell2mat(Atotal(:,6));
X5=cell2mat(Atotal(:,7));
mdl2 = fitlm(X1,X2,X3,X4,X5,Y1,'CategoricalVars',logical([1,2,3,4,5]));
But now it gives me a lt of errors:
Error using internal.stats.parseArgs (line 42)
Parameter name must be text.
Error in LinearModel.fit (line 849)
[intercept,predictorVars,responseVar,weights,exclude, ...
Error in fitlm (line 117)
model = LinearModel.fit(X,varargin{:});
Could someone help me? Thank you
I think there are two problems with your code.
The first problem is that fitlm expects the following arguments:
mdl = fitlm(X,y,modelspec)
which basically means that you have to collect your predictor variables into one matrix, and use it as its first argument. So you should do the following:
X = [X1, X2, X3, X4, X5];
fitlm(X, Y1, ...)
The second problem is that for the CategoricalVars argument fitlm expects either a logical vector (a vector which is one where the variable is categorical, and zero where continuous) or a numeric index vector. So the correct usage is:
X = [X1, X2, X3, X4, X5];
fitlm(X, Y1, 'CategoricalVars',logical([1,1,1,1,1]))
or
X = [X1, X2, X3, X4, X5];
fitlm(X, Y1, 'CategoricalVars', [1,2,3,4,5])
The above code snippets should work properly.
However you could consider declaring your categorical variables as categorical (if you have Matlab R2013b or above). In this case you would do the following:
X1 = categorical(cell2mat(Atotal(:,3)));
X2 = categorical(cell2mat(Atotal(:,4)));
X3 = categorical(cell2mat(Atotal(:,5)));
X4 = categorical(cell2mat(Atotal(:,6)));
X5 = categorical(cell2mat(Atotal(:,7)));
X = [X1, X2, X3, X4, X5];
fitlm(X, Y1)
The advantage of this approach is that Matlab knows that your Xi variables are categorical, and they will be treated accordingly, so you do not have to specify the CategoricalVars argument every time you want to run a regression.
Finally, the Matlab documentation of the fitlm function is really good with a lot of examples, so check that out too.
Note: as others have mentioned in the comments, you should also consider running a logit regression as your response variable is binary. In this case you would estimate your model the following way:
X = [X1, X2, X3, X4, X5];
fitglm(X, Y1, 'Distribution', 'binomial', 'Link', 'logit')
However if you do this be sure to understand what a logistic model is, what are its assumptions and what is the interpretation of its coefficients.
I have a 2 column vector with different lengths y1 and y2. I want to mixed them together in one matrix.
This matrix should have y1 and y2 as a rows, but they have different lengths. Is it possible to add 0 to shorter vector that it has the same length as longer one?
Many ways to do this, here is one:
>> y1 = [1;2;3;4;5];
>> y2 = [7;8;9];
>> z = zeros(2, max(length(y1), length(y2)));
>> z(1, 1:length(y1)) = y1;
>> z(2, 1:length(y2)) = y2
z =
1 2 3 4 5
7 8 9 0 0
vec2mat does that easily:
vec2mat([y1; y2], max(numel(y1), numel(y2)))