I have N lines that are defined by a y-intercept and an angle, q. The constraint is that all N lines must intersect at one point. The equations I can come up with to eventually get the constraint are these:
Y = tan(q(1))X + y(1)
Y = tan(q(2))X + y(2)
...
I can, by hand, get the constraint if N = 3 or 4 but I am having trouble just getting one constraint if N is greater than 4. If N = 3 or 4, then when I solve the equations above for X, I get 2 equations and then can just set them equal to each other. If N > 4, I get more than 2 equations that equal X and I dont know how to condense them down into one constraint. If I cannot condense them down into one constraint and am able to solve the optimization problem with multiple constraints that are created dynamically (depending on the N that is passed in) that would be fine also.
To better understand what I am doing I will show how I get the constraints for N = 3. I start off with these three equations:
Y = tan(q(1))X + y(1)
Y = tan(q(2))X + y(2)
Y = tan(q(3))X + y(3)
I then set them equal to each other and get these equations:
tan(q(1))X + y(1) = tan(q(2))X + y(2)
tan(q(2))X + y(2) = tan(q(3))X + y(3)
I then solve for X and get this constraint:
(y(2) - y(1)) / (tan(q(1)) - tan(q(2))) = (y(3) - y(2)) / (tan(q(2)) - tan(q(3)))
Notice how I have 2 equations to solve for X. When N > 4 I end up with more than 2. This is OK if I am able to dynamically create the constraints and then call an optimization function in MATLAB that will handle multiple constraints but so far have not found one.
You say the optimization algorithm needs to adjust q such that the "real" problem is minimized while the above equations also hold.
Note that the fifth Euclid axoim ensures that all lines will always intersect with all other lines, unless two qs are equal but the corresponding y0s are not. This last case is so rare (in a floating point context) that I'm going to skip it here, but for added robustness, you should eventually include it.
Now, first, think in terms of matrices. Your constraints can be formulated by the matrix equation:
y = tan(q)*x + y0
where q, y and y0 are [Nx1] matrices, x an unknown scalar. Note that y = c*ones(N,1), e.g., a matrix containing only the same constant. This is actually a non-linear constraint -- that is, it cannot be expressed as
A*q <= b or A*q == b
with A some design matrix and b some solution vector. So, you'll have to write a function defining this non-linear constraint, which you can pass on to an optimizer like fmincon. From the documentation:
x = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon) subjects the
minimization to the nonlinear inequalities c(x) or equalities ceq(x)
defined in nonlcon. fmincon optimizes such that c(x) ≤ 0 and ceq(x) =
0. If no bounds exist, set lb = [] and/or ub = [].
Note that you were actually going in the right direction. You can solve for the x-location of the intersection for any pair of lines q(n),y0(n) and q(m),y0(m) with the equation:
x(n,m) = (y0(n)-y0(m)) / (q(m)-q(n))
Your nonlcon function should find x for all possible pairs n,m, and check if they are all equal. You can do this conveniently something like so:
function [c, ceq] = nonlcon(q, y0)
% not using inequalities
c = -1; % NOTE: setting it like this will always satisfy this constraint
% compute tangents
tanq = tan(q);
% compute solutions to x for all pairs
x = bsxfun(#minus, y0, y0.') ./ -bsxfun(#minus, tanq, tanq.');
% equality contraints: they all need to be equal
ceq = diff(x(~isnan(x))); % NOTE: if all(ceq==0), converged.
end
Note that you're not actually solving for q explicitly (or need the y-coordinate of the intersection at all) -- that is all fmincon's job.
You will need to do some experimenting, because sometimes it is sufficient to define
x = x(~isnan(x));
ceq = norm(x-x(1)); % e.g., only 1 equality constraint
which will be faster (less derivatives to compute), but other problems really need
x = x(~isnan(x));
ceq = x-x(1); % e.g., N constraints
or similar tricks. It really depends on the rest of the problem how difficult the optimizer will find each case.
Related
I have inequalities with two unknown variables. So how could I assume one variable with different values and get the others?
For instance: -15<10*x+2*y<20.
How could I assume x=2, 3, and so on, and then find answer of (y) depending on the value of (x)?
I have been trying to apply the assume and find commands, but unfortunately, I could not. So I hope anyone could help me, please.
Looking forward to hearing from you.
I am new to Matlab, so I have been trying to apply solve, assume, and find commands
clear all;
clc;
syms x y real;
z=solve(-15<10*x+2*y,[x y])
b=solve(10*x+2*y<20,[x y])
yinterval = [ z,b]
I expect the output: to assume x=different numbers and then y= be a list of possible results depending on the value of x
Thanks,
For each value of x, technically there are infinite values of y that satisfy those equations, so for my solution, I assumed x and y were integer values. As well, it appears that you want to give the program a set of x values and have it calculate y values for each x value. Instead of using the solve command, we can simply use a couple of loops to find all satisfactory integer values of y for each value of x.
To start, we need to make a results matrix to store each x,y pair that satisfies the equations you've given. This is called pre-allocation, as we're pre-allocating the space needed to store our answers. Using the equations, we can deduce that there will be 17 satisfactory y values per x. So, our first two lines of code will be initializing the desired x-values and the results matrix:
xVec = 1:5; %x-vector, change this to whatever x-values you want to test
results = zeros(length(xVec)*14, 2); %results matrix
Note: If you decide to iterate x or y by a value different than +1 (more on that later), you'll need to come up with a different method of creating this results matrix. You could also just not pre-allocate the results matrix, but your code will run slower as the size of the results matrix will be changing on each loop.
Next are the loops. Admittedly, this is not the most elegant solution, but it'll get the job done. First, we need an index to keep up with where we are in our results matrix. This is pretty easy, we'll just call it index and start at 1 (since MATLAB indexes from 1 in matrices. Remember that!):
index = 1; %index for results matrix
Next, we need to loop through each value in our x-vector. Simply use a for loop:
for x = xVec
...
For each value of x, there is a minimum value of y. This value can be solved for in
-15 < 10*x + 2*y --> -14 = 10*x + 2*y_min
So, simply solving for y gives us our next line of code:
y = -7 - 5*x; %solving for y
Note: each time we iterate x in our for loop, a new starting value of y will be calculated.
Finally, we need to loop through values of y that still satisfy the inequalities given. This is performed through use of a while loop:
while 10*x + 2*y > -15 && 10*x + 2*y < 20
...
Note: && is the 'and' statement while using loops. You can't use a single equation for this (i.e. you can't say something like -15 < x < 20, you have to split them up using &&).
Since we solved for the first value of y, we can go ahead and record the current x and y values in our results matrix:
results(index, :) = [x, y]; %storing current x- and y-values
Then, we need to iterate y, as otherwise we'd be stuck in this while-loop forever.
y = y + 1;
Note: You can iterate this y-value with whatever amount you want. I chose to iterate by 1 each time, as I assumed you wanted to find integer values. Just change the +1 to whatever value you want.
Finally, we iterate our index, so that the next pair of x,y values that satisfy our equations don't overwrite our previous solutions.
index = index + 1;
All that's left is to close our loops and run! As I said, this isn't the most efficient solution, so I wouldn't use this for large amounts of x- and y-values. As well, like with iterating the y-values, the x-values can have any 'step-size' you want. As it's coded currently, it jumps +1 between each x, but changing the xVec input to any vector will still work (ex. xVec = 1:0.1:5; iterates the x-value by +0.1 each step instead of +1).
Here's the code all together, sans comments (since I wrote the comments while making the above code snippets):
xVec = 1:5;
results = zeros(length(xVec)*14, 2);
index = 1;
for x = xVec
y = -7 - 5*x;
while 10*x + 2*y > -15 && 10*x + 2*y < 20
results(index, :) = [x, y];
y = y + 1;
index = index + 1;
end
end
Let me know if you have any questions!
I need to numerically evaluate some integrals which are all of the form shown in this image:
These integrals are the matrix elements of a N x N matrix, so I need to evaluate them for all possible combinations of n and m in the range of 1 to N. The integrals are symmetric in n and m which I have implemented in my current nested for loop approach:
function [V] = coulomb3(N, l, R, R0, c, x)
r1 = 0.01:x:R;
r2 = R:x:R0;
r = [r1 r2];
rl1 = r1.^(2*l);
rl2 = r2.^(2*l);
sines = zeros(N, length(r));
V = zeros(N, N);
for i = 1:N;
sines(i, :) = sin(i*pi*r/R0);
end
x1 = length(r1);
x2 = length(r);
for nn = 1:N
for mm = 1:nn
f1 = (1/6)*rl1.*r1.^2.*sines(nn, 1:x1).*sines(mm, 1:x1);
f2 = ((R^2/2)*rl2 - (R^3/3)*rl2.*r2.^(-1)).*sines(nn, x1+1:x2).*sines(mm, x1+1:x2);
value = 4*pi*c*x*trapz([f1 f2]);
V(nn, mm) = value;
V(mm, nn) = value;
end
end
I figured that calling sin(x) in the loop was a bad idea, so I calculate all the needed values and store them. To evaluate the integrals I used trapz, but as the first and the second/third integrals have different ranges the function values need to be calculated separately and then combined.
I've tried a couple different ways of vectorization but the only one that gives the correct results takes much longer than the above loop (used gmultiply but the arrays created are enourmous). I've also made an analytical solution (which is possible assuming m and n are integers and R0 > R > 0) but these solutions involve a cosine integral (cosint in MATLAB) function which is extremely slow for large N.
I'm not sure the entire thing can be vectorized without creating very large arrays, but the inner loop at least should be possible. Any ideas would be be greatly appreciated!
The inputs I use currently are:
R0 = 1000;
R = 8.4691;
c = 0.393*10^(-2);
x = 0.01;
l = 0 # Can reasonably be 0-6;
N = 20; # Increasing the value will give the same results,
# but I would like to be able to do at least N = 600;
Using these values
V(1, 1:3) = 873,379900963549 -5,80688363271849 -3,38139152472590
Although the diagonal values never converge with increasing R0 so they are less interesting.
You will lose the gain from the symmetricity of the problem with my approach, but this means a factor of 2 loss. Odds are that you'll still benefit in the end.
The idea is to use multidimensional arrays, making use of trapz supporting these inputs. I'll demonstrate the first term in your figure, as the two others should be done similarly, and the point is the technique:
r1 = 0.01:x:R;
r2 = R:x:R0;
r = [r1 r2].';
rl1 = r1.'.^(2*l);
rl2 = r2.'.^(2*l);
sines = zeros(length(r),N); %// CHANGED!!
%// V = zeros(N, N); not needed now, see later
%// you can define sines in a vectorized way as well:
sines = sin(r*(1:N)*pi/R0); %//' now size [Nr, N] !
%// note that implicitly r is of size [Nr, 1, 1]
%// and sines is of size [Nr, N, 1]
sines2mat = permute(sines,[1, 3, 2]); %// size [Nr, 1, N]
%// the first term in V: perform integral along first dimension
%//V1 = 1/6*squeeze(trapz(bsxfun(#times,bsxfun(#times,r.^(2*l+2),sines),sines2mat),1))*x; %// 4*pi*c prefactor might be physics, not math
V1 = 1/6*permute(trapz(bsxfun(#times,bsxfun(#times,r.^(2*l+2),sines),sines2mat),1),[2,3,1])*x; %// 4*pi*c prefactor might be physics, not math
The key point is that bsxfun(#times,r.^(2*l+2),sines) is a matrix of size [Nr,N,1], which is again multiplied by sines2mat using bsxfun, the result is of size [Nr,N,N] and an element (k1,k2,k3) corresponds to an integrand at radial point k1, n=k2 and m=k3. Using trapz() with explicitly the first dimension (which would be default) reduces this to an array of size [1,N,N], which is just what you need after a good squeeze(). Update: as per #Dev-iL's comment you should use permute instead of squeeze to get rid of the leading singleton dimension, as that might be more efficent.
The two other terms can be handled the same way, and of course it might still help if you restructure the integrals based on overlapping and non-overlapping parts.
I have a linear equation:
vt = v1*x1 + v2*x2 + v3*x3
vt, v1, v2, v3 are scalars with values between 0 and 1. What is the best way to generate one set (any set will be fine) of x1, x2 and x3 that satisfy the equation above. and also satisfy
x1>0
x2>0
x3>0
I have couple thousand sets of vt,v1,v2 and v3, therefore I need to be able to generate x1, x2 and x3 programmatically.
There are two ways you could approach this:
From the method that you have devised in your post. Randomly generate x1 and x2 and ensure that vt < v1*x1 + v2*x2, then go ahead and solve for x3.
Formulate this into linear program. A linear program is basically solving a system of equations that are subject to inequality or equality constraints. In other words:
As such, we can translate your problem to be of a linear programming problem. The "maximize" statement is what is known as the objective function - the overall goal of what you are trying to accomplish. In linear programming problems, we are trying to minimize or maximize this objective. To do this, we must satisfy the inequalities seen in the subject to condition. Usually, this program is represented in canonical form, and so the constraints on each variable should be positive.
The maximize condition can be arbitrary as you don't care about the objective. You just care about any solution. This whole paradigm can be achieved by linprog in MATLAB. What you should be careful with is how linprog is specified. In fact, the objective is minimized instead of maximized. The conditions, however, are the same with the exception of ensuring that all of the variables are positive. We will have to code that in ourselves.
In terms of the arbitrary objective, we can simply do x1 + x2 + x3. As such, c = [1 1 1]. Our equality constraint is: v1*x1 + v2*x2 + v3*x3 = vt. We also must make sure that x is positive. In order to code this in, what we can do is choose a small constant so that all values of x are greater than this value. Right now, linprog does not support strict inequalities (i.e. x > 0) and so we have to circumvent this by doing this trick. Also, to ensure that the values are positive, linprog assumes that the Ax <= b. Therefore, a common trick that is used is to negate the inequality of x >= 0, and so this is equivalent to -x <= 0. To ensure the values are non-zero, we would actually do: -x <= -eps, where eps is a small constant. However, when I was doing experiments, by doing it this way, two of the variables end up to be the same solution. As such, what I would recommend we do is to generate good solutions that are random each time, let's draw b to be from a uniform random distribution as you said. This will then give us a starting point every time we want to solve this problem.
Therefore, our inequalities are:
-x1 <= -rand1
-x2 <= -rand2
-x3 <= -rand3
rand1, rand2, rand3 are three randomly generated numbers that are between 0 and 1. In matrix form, this is:
[-1 0 0][x1] [-rand1]
[0 -1 0][x2] <= [-rand2]
[0 0 -1][x3] [-rand3]
Finally, our equality constraint from before is:
[v1 v2 v3][x1] [vt]
[x2] =
[x3]
Now, to use linprog, you would do this:
X = linprog(c, A, b, Aeq, beq);
c is a coefficient array that is defined for the objective. In this case, it would be defined as [1 1 1], A and b is the matrix and column vector defined for the inequality constraints and Aeq and beq is the matrix and column vector defined for the equality constraints. X would thus give us the solution after linprog converges (i.e. x1, x2, x3). As such, you would do this:
A = -eye(3,3);
b = -rand(3,1);
Aeq = [v1 v2 v3];
beq = vt;
c = [1 1 1];
X = linprog(c, A, b, Aeq, beq);
As an example, suppose v1 = 0.33, v2 = 0.5, v3 = 0.2, and vt = 2.5. Therefore:
rng(123); %// Set seed for reproducibility
v1 = 0.33; v2 = 0.5; v3 = 0.2;
vt = 2.5;
A = -eye(3,3);
b = -rand(3,1);
Aeq = [v1 v2 v3];
beq = vt;
c = [1 1 1];
X = linprog(c, A, b, Aeq, beq);
I get:
X =
0.6964
4.4495
0.2268
To verify that this equals vt, we would do:
s = Aeq*X
s = 2.5000
The above simply does v1*x1 + v2*x2 + v3*x3. This is computed in a dot product form to make things easy as X is a column vector and v1, v2, v3 are already set in Aeq and is a row vector.
As such, either way is good, but at least with linprog, you don't have to keep looping until you get that condition to be satisfied!
Small Caveat
One small caveat that I forgot to mention in the above approach is that you need to make sure that vt >= v1*rand1 + v2*rand2 + v3*rand3 to ensure convergence. Since you said that v1,v2,v3 are bounded between 0 and 1, the worst case is when v1,v2,v3 are all equal to 1. As such, we really need to make sure that vt > rand1 + rand2 + rand3. If this is not the case, then simply take each value of rand1, rand2, rand3, and divide by (rand1 + rand2 + rand3) / vt. As such, this will ensure that the total summation will equal vt assuming that all of the weights are 1, and this will allow the linear program to converge properly.
If you don't, then the solution will not converge due to the inequality conditions placed in for b, and you won't get the right answer. Just some food for thought! As such, do this for b before you run linprog
if sum(-b) > vt
b = b ./ (sum(-b) / vt);
end
Good luck!
Say I have two functions f(x), g(x), and a vector:
xval=1:0.01:2
For each of these individual x values, I want to define a vector of y-values, covering the y-interval bounded by the two functions (or possibly a matrix where columns are x-values, and rows are y-values).
How would I go about creating a loop that would handle this for me? I have absolutely no idea myself, but I'm sure some of you have something right up your sleeve. I've been sweating over this problem for a few hours by now.
Thanks in advance.
Since you wish to generate a matrix, I assume the number of values between f(x) and g(x) should be the same for every xval. Let's call that number of values n_pt. Then, we also know what the dimensions of your result matrix rng will be.
n_pt = 10;
xval = 1 : 0.01 : 2;
rng = zeros(n_pt, length(xval));
Now, into the loop. Once we know what the y-values returned by f(x) and g(x) are, we can use linspace to give us n_pt equally spaced points between them.
for n = 1 : length(xval)
y_f = f(xval(n))
y_g = g(xval(n))
rng(:, n) = linspace(y_f, y_g, n_pt)';
end
This is nice because with linspace you don't need to worry about whether y_f > y_g, y_f == y_g or y_f < y_g. That's all taken care of already.
For demsonstration, I run this example for xval = 1 : 0.1 : 2 and the two sinusoids f = #(x) sin(2 * x) and g = #(x) sin(x) * 2. The points are plotted using plot(xval, rng, '*k');.
I'm trying to use MatLab code as a way to learn math as a programmer.
So reading I'm this post about subspaces and trying to build some simple matlab functions that do it for me.
Here is how far I got:
function performSubspaceTest(subset, numArgs)
% Just a quick and dirty function to perform subspace test on a vector(subset)
%
% INPUT
% subset is the anonymous function that defines the vector
% numArgs is the the number of argument that subset takes
% Author: Lasse Nørfeldt (Norfeldt)
% Date: 2012-05-30
% License: http://creativecommons.org/licenses/by-sa/3.0/
if numArgs == 1
subspaceTest = #(subset) single(rref(subset(rand)+subset(rand))) ...
== single(rref(rand*subset(rand)));
elseif numArgs == 2
subspaceTest = #(subset) single(rref(subset(rand,rand)+subset(rand,rand))) ...
== single(rref(rand*subset(rand,rand)));
end
% rand just gives a random number. Converting to single avoids round off
% errors.
% Know that the code can crash if numArgs isn't given or bigger than 2.
outcome = subspaceTest(subset);
if outcome == true
display(['subset IS a subspace of R^' num2str(size(outcome,2))])
else
display(['subset is NOT a subspace of R^' num2str(size(outcome,2))])
end
And these are the subset that I'm testing
%% Checking for subspaces
V = #(x) [x, 3*x]
performSubspaceTest(V, 1)
A = #(x) [x, 3*x+1]
performSubspaceTest(A, 1)
B = #(x) [x, x^2, x^3]
performSubspaceTest(B, 1)
C = #(x1, x3) [x1, 0, x3, -5*x1]
performSubspaceTest(C, 2)
running the code gives me this
V =
#(x)[x,3*x]
subset IS a subspace of R^2
A =
#(x)[x,3*x+1]
subset is NOT a subspace of R^2
B =
#(x)[x,x^2,x^3]
subset is NOT a subspace of R^3
C =
#(x1,x3)[x1,0,x3,-5*x1]
subset is NOT a subspace of R^4
The C is not working (only works if it only accepts one arg).
I know that my solution for numArgs is not optimal - but it was what I could come up with at the current moment..
Are there any way to optimize this code so C will work properly and perhaps avoid the elseif statments for more than 2 args..?
PS: I couldn't seem to find a build-in matlab function that does the hole thing for me..
Here's one approach. It tests if a given function represents a linear subspace or not. Technically it is only a probabilistic test, but the chance of it failing is vanishingly small.
First, we define a nice abstraction. This higher order function takes a function as its first argument, and applies the function to every row of the matrix x. This allows us to test many arguments to func at the same time.
function y = apply(func,x)
for k = 1:size(x,1)
y(k,:) = func(x(k,:));
end
Now we write the core function. Here func is a function of one argument (presumed to be a vector in R^m) which returns a vector in R^n. We apply func to 100 randomly selected vectors in R^m to get an output matrix. If func represents a linear subspace, then the rank of the output will be less than or equal to m.
function result = isSubspace(func,m)
inputs = rand(100,m);
outputs = apply(func,inputs);
result = rank(outputs) <= m;
Here it is in action. Note that the functions take only a single argument - where you wrote c(x1,x2)=[x1,0,x2] I write c(x) = [x(1),0,x(2)], which is slightly more verbose, but has the advantage that we don't have to mess around with if statements to decide how many arguments our function has - and this works for functions that take input in R^m for any m, not just 1 or 2.
>> v = #(x) [x,3*x]
>> isSubspace(v,1)
ans =
1
>> a = #(x) [x(1),3*x(1)+1]
>> isSubspace(a,1)
ans =
0
>> c = #(x) [x(1),0,x(2),-5*x(1)]
>> isSubspace(c,2)
ans =
1
The solution of not being optimal barely scratches the surface of the problem.
I think you're doing too much at once: rref should not be used and is complicating everything. especially for numArgs greater then 1.
Think it through: [1 0 3 -5] and [3 0 3 -5] are both members of C, but their sum [4 0 6 -10] (which belongs in C) is not linear product of the multiplication of one of the previous vectors (e.g. [2 0 6 -10] ). So all the rref in the world can't fix your problem.
So what can you do instead?
you need to check if
(randn*subset(randn,randn)+randn*subset(randn,randn)))
is a member of C, which, unless I'm mistaken is a difficult problem: Conceptually you need to iterate through every element of the vector and make sure it matches the predetermined condition. Alternatively, you can try to find a set such that C(x1,x2) gives you the right answer. In this case, you can use fminsearch to solve this problem numerically and verify the returned value is within a defined tolerance:
[s,error] = fminsearch(#(x) norm(C(x(1),x(2)) - [2 0 6 -10]),[1 1])
s =
1.999996976386119 6.000035034493023
error =
3.827680714104862e-05
Edit: you need to make sure you can use negative numbers in your multiplication, so don't use rand, but use something else. I changed it to randn.