Matlab - Symbolically Solving Inequalities - matlab

So, I'm trying to establish some new stability criteria for my simulations, and this involves a lot of convoluted inequalities. I've worked through the math a few times by hand, and it's very laborous; so, I wanted to figure out a way to automate the process (as I'm trying to find the best integration scheme from a stability perspective). Is there anyway to solve inequalities symbolically in Matlab? Here's what I'm trying to solve. In the following expression, x refers to the gradient of a force function with respect to x, and t is the time step. In general, x < 0 and t > 0:
-(t*x + (2*t^3*x + t^2*x^2 - 2*t*x + 4*t + 1)^(1/2) + 1)/(x*t^2 - 2) < 1
Based on what I've looked at online, this seems to be possible in MuPAD, but using the following code does not give me any valid results:
solve(-(t*x + (2*t^3*x + t^2*x^2 - 2*t*x + 4*t + 1)^(1/2) + 1)/(x*t^2 - 2) < 1, t)
Any idea what I can do to make this work and automate the process?

First, since Wolfram Alpha gives you an answer (that I presume you've checked for correctness), I assume you want to use Matlab to solve other similar problems. However, this is a very non-trivial inequality due to the roots of the polynomials. I haven't been able to get Matlab/MuPAD to do anything with it. As I stated, regular Matlab can solve inequalities and systems of equalities in many cases, e.g., in R2013b
syms x real;
solve(x^3-1>1,x)
Even Mathematica 9 has trouble (the Reduce function can be used instead of it's Solve, but the output is not easy to use).
You can, however, solve for the real roots where x < 0 and t > 0 via
syms x t real;
assume(x<0);
assume(t>0);
f = -(t*x+sqrt(2*t^3*x+t^2*x^2-2*t*x+4*t+1)+1)/(x*t^2-2);
s = solve(f==1,t)
which returns:
s =
-(x + (x*(x - 2))^(1/2))/x
This simplifies to sqrt((x-2)/x)-1. Thus t > sqrt((x-2)/x)-1, one of the bounds provided by Wolfram Alpha. (The other more complicated bound is always less than zero and actually is the condition that ensures that t is real.)
But, do you even need to be solving this problem symbolically? Do you need explicit expressions for the various intervals in terms of all x? If not, this type of problem is probably better suited numeric approaches – either via root solving (e.g., fzero) or minimization (e.g., fmincon).

Related

Indefinite integration with Matlab's Symbolic Toolbox - complex solution

I'm using Matlab 2014b. I've tried:
clear all
syms x real
assumeAlso(x>=5)
This returned:
ans =
[ 5 <= x, in(x, 'real')]
Then I tried:
int(sqrt(x^2-25)/x,x)
But this still returned a complex answer:
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5*i)/x)*5*i
I tried the simplify command, but still a complex answer. Now, this might be fixed in the latest version of Matlab. If so, can people let me know or offer a suggestion for getting the real answer?
The hand-calculated answer is sqrt(x^2-25)-5*asec(x/5)+C.
This behavior is present in R2017b, though when converted to floating point the imaginary components are different.
Why does this occur?
This occurs because Matlab's int function returns the full general solution when you ask for the indefinite integral. This solution is valid over the entire domain of of real values, including your restricted domain of x>=5.
With a bit of math you can show that the solution is always real for x>=5 (see complex logarithm). Or you can use more symbolic math via the isAlways function to show this:
syms x real
assume(x>=5)
y = int(sqrt(x^2-25)/x, x)
isAlways(imag(y)==0)
This returns true (logical 1). Unfortunately, Matlab's simplification routines appear to not be able to reduce this expression when assumptions are included. You might also submit this case to The MathWorks as a service request in case they'd consider improving the simplification for this and similar equations.
How can this be "fixed"?
If you want to get rid of the zero-valued imaginary part of the solution you can use sym/real:
real(y)
which returns 5*atan2(5, (x^2-25)^(1/2)) + (x^2-25)^(1/2).
Also, as #SardarUsama points out, when the full solution is converted to floating point (or variable precision) there will sometimes numeric imprecision when converting from exact symbolic form. Using the symbolic real form above should avoid this.
The answer is not really complex.
Take a look at this:
clear all; %To clear the conditions of x as real and >=5 (simple clear doesn't clear that)
syms x;
y = int(sqrt(x^2-25)/x, x)
which, as we know, gives:
y =
(x^2 - 25)^(1/2) - log(((x^2 - 25)^(1/2) + 5i)/x)*5i
Now put some real values of x≥5 to check what result it gives:
n = 1004; %We'll be putting 1000 values of x in y from 5 to 1004
yk = zeros(1000,1); %Preallocation
for k=5:n
yk(k-4) = subs(y,x,k); %Putting the value of x
end
Now let's check the imaginary part of the result we have:
>> imag(yk)
ans =
1.0e-70 *
0
0
0
0
0.028298997121333
0.028298997121333
0.028298997121333
%and so on...
Notice the multiplier 1e-70.
Let's check the maximum value of imaginary part in yk.
>> max(imag(yk))
ans =
1.131959884853339e-71
This implies that the imaginary part is extremely small and it is not a considerable amount to be worried about. Ideally it may be zero and it's coming due to imprecise calculations. Hence, it is safe to call your result real.

MATLAB's Symbolic Math Fails to Solve a Simple Inequality

I have a simple inequality and MATLAB's Symbolic Math toolbox is doing something very strange. Here are the variables:
>> syms X ndot4B xiA ndot4A xiB
I'm trying to solve the following inequality (please do it yourself "on paper"):
>> solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0, xiA)
The answer is:
ans =
(X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B)
But this is not correct. If instead I solve it as an equality:
>> solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB, xiA)
The result is:
ans =
(X*ndot4A*xiB)/(ndot4B - X*ndot4B)
The above is correct (i.e., xiA has to be greater than the solution above). The difference is in the numerator. Maple gets it right (as it should). Any ideas on what may be going on? It's hard to believe that MATLAB would screw up on such simple calculation.
EDIT:
Based on horchler's answer, I tried solving the same inequality using assumptions on both MATLAB and Maple.
MATLAB:
Maple:
I still find MATLAB's answer very strange...
Your system is ill-defined. You (and perhaps Maple) are making some assumptions that aren't necessarily true or that are at least different from each other. When solving inequalities, it's best to use the 'ReturnConditions' option to see the full details of the solution. In your case:
syms X xiA ndot4B ndot4A xiB
s = solve(X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0, xiA, 'ReturnConditions', true)
This returns a data structure:
xiA: [1x1 sym]
parameters: [1x1 sym]
conditions: [1x1 sym]
Now you'll see that there is an additional parameter (s.parameters is x) and set of conditions (s.conditions is X ~= 1 & ndot4B ~= 0 & 0 < x). The solution, s.xiA, is a function of the parameter:
-(x - X*ndot4A*xiB)/(ndot4B - X*ndot4B)
Because you are solving this with the strict inequality (> rather than >=), the parameter x can't actually be equal to zero to guarantee satisfying the inequality (Maple may treat the two cases the same, I'm not sure).
So why does Matlab's symbolic engine (not quite the same as the MuPAD environment) return (X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B) when you don't ask for the return conditions? Firstly, this answer satisfies the inequality and is perfectly valid given that there is no information (assumptions) about the ranges of each variable. Rather than return an error or warning, it looks like Matlab just chose the first integer value of the parameter x that would satisfy the conditions, i.e., 1. It appears to treat the <= case similarly, but for some reason does not choose 0 for x (which would match the ==). I suggest filing a service request if you want to try to ask The MathWorks why this is and if it might be a bug of some sort.
I also recommend learning about and using assumptions when working with solve.
solve's answer is correct. You simply need some positive value in the numerator to satisfy the inequality. It can be any value, hence solve introduces a parameter.
You can verify your proposed answer and solve's answer as:
syms X ndot4B xiA ndot4A xiB
eqn = X*ndot4B*xiA - ndot4B*xiA + X*ndot4A*xiB > 0;
trySol = (X*ndot4A*xiB)/(ndot4B - X*ndot4B); % let's try the proposed answer
tryCondition = subs(eqn,xiA,trySol); % substitute the answer to get the condition
isAlways(tryCondition) % check if the condition holds?
ans =
logical
0
The condition doesn't hold. Now try solve's answer with the same steps:
trySol = (X*ndot4A*xiB - 1)/(ndot4B - X*ndot4B);
tryCondition = subs(eqn,xiA,trySol);
isAlways(tryCondition)
ans =
logical
1
This answer is correct. You can check on paper yourself by substituting these two values for xiA. You just need some positive value in the numerator to satisfy the > inequality. For example, even using eps instead of 1 will work:
trySol = (X*ndot4A*xiB - eps)/(ndot4B - X*ndot4B);
isAlways(subs(eqn,xiA,trySol))
ans =
logical
1
As horchler pointed out, if you change the > to ==, then you don't need the positive value.
solve introduces assumptions, X~=1 and ndot4B~=0, because when you divide both sides of an inequality by a constant, then that constant cannot be 0.
Hope this helps.

Unable to code non linear equation in MATLAB R2013a - MATLAB giving warning message

I wanted to solve the following equation in MATLAB R2013a using the Symbolic Math Toolbox.
(y/x)-(((1+r)^n)-1)/r=0 where y,x and n>3 are given and r is the dependent variable
I tried myself & coded as follows:
f=solve('(y/x)-(((1+r)^n)-1)/r','r')
but as the solution for r is not exact i.e. it is converging on successive iterations hence MATLAB is giving a warning output with the message
Warning: Explicit solution could not be found.
f =
[ empty sym ]
How do I code this?
There are an infinite number of solutions to this for an unspecified value of n > 3 and unknown r. I hope that it's pretty clear why – it's effectively asking for a greater and greater number of roots of (1+r)^n. You can find solutions for fixed values of n, however. Note that as n becomes larger there are more and more solutions and of course some of them are complex. I'm going to assume that you're only interested in real values of r. You can use solve and symbolic math for n = 4, n = 5, and n = 6 (for n = 6, the solution may not be in a convenient form):
y = 441361;
x = 66990;
n = 5;
syms r;
rsol = solve(y/x-((1+r)^n-1)/r==0,r,'IgnoreAnalyticConstraints',true)
double(rsol)
However, the question is "do you need all the solutions or just a particular solution for a given value of n"? If you just need a particular solution, you shouldn't be using symbolic math at all as it's slower and has practical issues like the ones you're experiencing. You can instead just use a numerical approach to find a zero of the equation that is near a specified initial guess. fzero is the standard function for solving this sort of problem in a single variable:
y = 441361;
x = 66990;
n = 5;
f = #(r)y/x-((1+r).^n-1)./r;
r0 = 1;
rsol = fzero(f,r0)
You'll see that the value returned is the same as one of the solutions from the symbolic solution above. If you adjust the initial guess r0 (say r0 = -3), it will return the other solution. When using numeric approaches in cases when there are multiple solutions, if you want specific solutions you'll need to know about the behavior of your function and you'll need to add some clever extra code to choose initial guesses.
I think you forgot to define n as well.
f=solve('(y/x)-(((1+r)^n)-1)/r=0','n-3>0','r','n')
Should solve your problem :)

Issue with Matlab solve function?

The following command
syms x real;
f = #(x) log(x^2)*exp(-1/(x^2));
fp(x) = diff(f(x),x);
fpp(x) = diff(fp(x),x);
and
solve(fpp(x)>0,x,'Real',true)
return the result
solve([0.0 < (8.0*exp(-1.0/x^2))/x^4 - (2.0*exp(-1.0/x^2))/x^2 -
(6.0*log(x^2)*exp(-1.0/x^2))/x^4 + (4.0*log(x^2)*exp(-1.0/x^2))/x^6],
[x == RD_NINF..RD_INF])
which is not what I expect.
The first question: Is it possible to force Matlab's solve to return the set of all solutions?
(This is related to this question.) Moreover, when I try to solve the equation
solve(fpp(x)==0,x,'Real',true)
which returns
ans =
-1.5056100417680902125994180096313
I am not satisfied since all solutions are not returned (they are approximately -1.5056, 1.5056, -0.5663 and 0.5663 obtained from WolframAlpha).
I know that vpasolve with some initial guess can handle this. But, I have no idea how I can generally find initial guessed values to obtain all solutions, which is my second question.
Other solutions or suggestions for solving these problems are welcomed.
As I indicated in my comment above, sym/solve is primarily meant to solve for analytic solutions of equations. When this fails, it tries to find a numeric solution. Some equations can have an infinite number of numeric solutions (e.g., periodic equations), and thus, as per the documentation: "The numeric solver does not try to find all numeric solutions for [the] equation. Instead, it returns only the first solution that it finds."
However, one can access the features of MuPAD from within Matlab. MuPAD's numeric::solve function has several additional capabilities. In particular is the 'AllRealRoots' option. In your case:
syms x real;
f = #(x)log(x^2)*exp(-1/(x^2));
fp(x) = diff(f(x),x);
fpp(x) = diff(fp(x),x);
s = feval(symengine,'numeric::solve',fpp(x)==0,x,'AllRealRoots')
which returns
s =
[ -1.5056102995536617698689500437312, -0.56633904710786569620564475006904, 0.56633904710786569620564475006904, 1.5056102995536617698689500437312]
as well as a warning message.
My answer to this question provides other way that various MuPAD solvers can be used, particularly if you can isolate and bracket your roots.
The above is not going to directly help with your inequalities other than telling you where the function changes sign. For those you could try:
s = feval(symengine,'solve',fpp(x)>0,x,'Real')
which returns
s =
(Dom::Interval(0, Inf) union Dom::Interval(-Inf, 0)) intersect solve(0 < 2*log(x^2) - 3*x^2*log(x^2) + 4*x^2 - x^4, x, Real)
Try plotting this function along with fpp.
While this is not a bug per se, The MathWorks still might be interested in this difference in behavior and poor performance of sym/solve (and the underlying symobj::solvefull) relative to MuPAD's solve. File a bug report if you like. For the life of me I don't understand why they can't better unify these parts of Matlab. The separation makes not sense from the perspective of a user.

YALMIP is returning that a program is infeasible when it is not

I'm having a problem trying to use YALMIP; I suspect I'm doing something silly and I would greatly appreciate if someone pointed out what it is.
I'm trying to solve some SDPs. When I don't define an objective, YALMIP returns a solution (implying that the problem is feasible). However, when I attach an objective to it, YALMIP returns that the problem is infeasible, which has left me a bit perplexed.
Here's the code for the simplest SDP I could cook up in which the above happens. Declaring the variables and setting the constraints is as follows:
y = sdpvar(6,1);
M = sdpvar(3,3);
C = [0,0,0,0,0,0; 0,0,0,0,0,0; -2,0,1.8,0,2,1; 0,0,0,0,0,0; 1,0,-1,0,-1.2,0;
0,0,0,0,0,0;];
F = [C*y==0, y(6) == 1, M>=0];
F = [F,M(1,1) == y(1), M(2,1) == y(2), M(3,1) == y(3),...
M(2,2) == y(4), M(3,2) == y(5), M(3,3) == y(6)];
Now if I merely ask YALMIP to find a feasible solution with
solvesdp(F)
it returns
info: 'Successfully solved (LMILAB)'
problem: 0
and some feasible M and y (I've checked that they indeed are). However, if I append the objective "minimise y(3)" (or indeed any linear combination of the entries of y) with
solvesdp(F,y(3))
it returns that the problem is infeasible:
info: 'Infeasible problem (LMILAB)'
problem: 1
and y and M are full of "NaN" tokens.
Many thanks in advance.
LMILAB should not be used together with YALMIP.
http://users.isy.liu.se/johanl/yalmip/pmwiki.php?n=Solvers.LMILAB
The solver in LMILAB has many deficiencies, and one which becomes crucial here is the fact that the solver lacks support for inequalities. To circumvent this, YALMIP adds double-sided inequalities, which completely destroys the numerical procedures of LMILAB.
Install a more general (and modern) solver such as SeDuMi, SDPT3, or Mosek
http://users.isy.liu.se/johanl/yalmip/pmwiki.php?n=Category.SemidefiniteProgrammingSolver
BTW, you are redundantly defining additional variables y. No reason to have them as separate decision variables and then encode how they relate to M. Simply extract them
y = M(find(tril(ones(3))));