Sympy library solve to an unknown variable - python

I have derived some equations with some variables. I want to solve to an unknown variable. I am using Sympy. My code is as follows:
import sympy as syp
import math as m
#this is the unknown variable that I want to find
C0 = syp.Symbol('C0')
#Known variables
D0 = 0.874
theta2 = 10.0
fi2 = 80.0
theta1 = (theta2/180.0)*m.pi
fi1 = (fi2/180.0)*m.pi
#Definitions of 6 different equations all of them in respect to CO.
C_t = 5*m.pi*(D0+4*C0)
St123 = 1.5*theta1*(D0+2*C0)
St45 = fi1*(D0+7*C0)
l1 = syp.sqrt((0.5*(D0+4*C0)-0.5*D0*m.cos(theta1))**2 + (0.5*D0*m.sin(theta1))**2)
l2 = syp.sqrt((0.5*(D0+6*C0)-0.5*(D0+2*C0)*m.cos(theta1))**2 + (0.5*(D0+2*C0)*m.sin(theta1))**2)
l3 = syp.sqrt((0.5*(D0+8*C0)-0.5*(D0+4*C0)*m.cos(theta1))**2 + (0.5*(D0+4*C0)*m.sin(theta1))**2)
#Definition of the general relationship between the above functions. Here C0 is unknown and C_b
C_b = C_t + 6*C0 + 3*(l1+l2+l3) - 3*St123 - 3*St45
#for C_b = 10.4866, find C0
syp.solve(C_b - 10.4866, C0)
As observed, I want to solve the C_b relationship to C0. Until the last line my code works fine. When I ran the whole script it seems that takes ages to calculate the C0. I dont have any warning message but I dont have any solution either. Would anybody suggest an alternative or a possible solution? Thanks a lot in advance.

As I have mentioned in a comment this problem is numerical in nature, so it is better to try to solve it with numpy/scipy. Nonetheless it is an amusing example of how to do numerics in sympy so here is one suggested workflow.
First of all, if it was not for the relative complexity of the expressions here, scipy would have been definitely the better option over sympy. But the expression is rather complicated, so we can first simplify it in sympy and only then feed it to scipy:
>>> C_b
38.0∗C0
+3.0∗((0.17∗C0+0.076)∗∗2+(2.0∗C0+0.0066)∗∗2)∗∗0.5
+3.0∗((0.35∗C0+0.076)∗∗2+(2.0∗C0+0.0066)∗∗2)∗∗0.5
+3.0∗((2.0∗C0+0.0066)∗∗2+0.0058)∗∗0.5
+9.4
>>> simplify(C_b)
38.0∗C0
+3.0∗(4.0∗C0∗∗2+0.027∗C0+0.0058)∗∗0.5
+3.0∗(4.1∗C0∗∗2+0.053∗C0+0.0058)∗∗0.5
+3.0∗(4.2∗C0∗∗2+0.08∗C0+0.0058)∗∗0.5
+9.4
Now given that you are not interested in symbolics and that the simplification was not that good, it would be useless to continue using sympy instead of scipy, but if you insist you can do it.
>>> nsolve(C_b - 10.4866, C0, 1) # for numerical solution
0.00970963412692139
If you try to use solve instead of nsolve you will just waste a lot of resources in searching for a symbolic solution (that may not even exist in elementary terms) when a numeric one is instantaneous.

Related

Solve algebraic equation in SymPy

I am trying to solve simple algebraic parametrized equation sqrt(x)=sqrt(a)+1 with SymPy command solveset:
x, a = symbols("x a")
solveset(Eq(sqrt(x), sqrt(a)+1), x)
It returns as part of answer (conditional set) two solutions: 2*sqrt(a)+a+1 and -2*sqrt(a)+a+1. I can't understand how we can obtain the second one with minus sign from our equation!
Command solve in the same time gives us only solution (sqrt(a) + 1)**2, which is correct in my opinion.
What happens with solveset, any ideas?
The issue is to do with the sets you are solving over. Specifically, solveset defaults to a complex domain, resulting in extraneous solutions due to the complex square root. But by explicitly specifying a real domain and defining a and x to both be positive (as we're just dealing with reals, so can't have a or x negative), the desired solution can be extracted:
x, a = symbols('x a', positive=True)
solveset(Eq(sqrt(x), sqrt(a) + 1), x, domain=S.Reals).as_relational(x).expand()
# x = 2⋅√a + a + 1
The method that solveset uses gives two roots to consider but checksol is not able to show that the 2nd solution is not generally valid so to be safe, it returns both and shows you the condition which must be checked. If you substitute a value in for a you will obtain a set with the single concrete answer.

Numerically stable way to compute conditional covariance matrix using linalg.solve

I know that the recommendation is not to use linalg.inv and use linalg.solve when inverting matrices. This makes sense when I have situation like Ax = b and I want to get x, but is there a way to compute something like: A - B * D^{-1} * C without using linalg.inv? Or what is the most numerically stable way to deal with the inverse in the expression?
Thanks!
Please don't inv—it's not as bad as most people think, but there's easier ways: you mentioned how np.linalg.solve(A, b) equals A^{-1} . b, but there's no requirement on what b is. You can use solve to solve your question, A - np.dot(B, np.linalg.solve(D, C)).
(Note, if you're doing blockwise matrix inversion, C is likely B.transpose(), right?)

Simplifying large symbolic expressions

I am working on creating a function that does the Legendre transform of an equation using sympy. I am trying to get the code to simplify the expression, but the simplification function won't work (I assume because of the size of the expression). This is for a general Legendre transformation, so I can't tell it to look for specific simplification.
As and example one output equation has the trig relation:
sin^2 = 1 - cos^2
To set up the problem
import sympy as sy
x, y, m1, m2, n, q1, q2, tht = sy.symbols("x, y, m1, m2, n, q1, q2, tht")
When I code that and use trigsimp()
a = x - x*sy.cos(tht)**2
print(sy.trigsimp(a))
I get
x*sin(tht)**2
like I should. However, when I put it into a more complex problem.
b = y*n**2/(x**2*y**2*(-m1 - m2*sy.cos(q1 - q2)**2 + m2))
print(sy.trigsimp(b))
I doesn't recognize the trig relationship and outputs:
n**2/(x**2*y*(-m1 - m2*cos(q1 - q2)**2 + m2))
Is there any way to simplify a large expression, or is there something betting than sympy I could use for this application?
edit:
To clarify the problem, a moderate amount of complexity seems to stump trigsimp(), shown by example b not being simplified properly. I am looking for a way to have a more rigorous simplification of the equation. For scale, the functions that I really want to simplify are 3-20 times larger than example b.
When working with larger expression it is normally better to give more direct instructions for simplification e.g.
In [18]: b.replace(cos, lambda a: sqrt(1-sin(a)**2)).collect(m2)
Out[18]:
2
n
─────────────────────────────
2 ⎛ 2 ⎞
x ⋅y⋅⎝-m₁ + m₂⋅sin (q₁ - q₂)⎠
That might not work in your actual problem but something should. The difficulty with generic routines like trigsimp and simplify is that there isn't a universally correct strategy for simplification so they have to try lots of things which is ends up being either slow or incomplete (or both). In fact it's not always clear what the "simplest" answer should be. The improvement in this example seems pretty marginal.

Sympy: solve for fraction

I have an equation and I need to solve it for a fraction.
I have more complex fomulas to solve but here is a minimal example: take the following simple function Y = X*a.
I want to solve for Y/X, so I expect Y/X =a.
Here is the code, it produces an empty set of answers
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
I guess I'm misunderstanding something, any help appreciated!
The solve function can solve for sub-expressions provided they appear "as is" in the equation being solved. For example, in the following code, solve returns an empty solution for testEq but it returns the correct solution for testEq2 which is the same equation rearranged in terms of Y/X.
from sympy import *
X,Y,a = symbols('X Y a')
testEq = Eq(Y,X*a)
solve(testEq,Y/X)
testEq2 = Eq( Y/X, a )
sol = solve(testEq2,Y/X)
This is not weird or unreasonable at all. If you look at the source code of the solve function it uses code like
>>> testEq.has( Y/X ) # returns False
>>> testEq2.has( Y/X ) # returns True
to check if the symbol ( or sympy object ) that we are solving is present in the equation. If SymPy had to check for all possible ways in which the symbols of an expression can be combined into sub-expressions, the code would become extremely complicated for something which can be easily achieved in other ways ( like solving for Y and dividing by X, in this example ).
Packages for symbolic computations are there to help us handle complicated mathematical equations. But they are not a substitute for human intelligence. More often than not, we need to guide these packages to help them give the answer in a form we want while working around their limitations.
In this issue, a focus routine handles such a request once an auxiliary expression is added to the one of interest:
>>> eq = Eq(y, x*a)
>>> aux = Eq(b, y/x)
>>> focus((aux, eq), b)
{b: a}
Such a routine does not eliminate the need for human intervention, it just assists by allowing the user to state the relationship of interest and add that to the current equation(s) from which the implications are then deduced/solved.

Building dict combinations to match a target sum in Python

I have a dict made of N integer values like this:
units = {'trooper':2, 'tank':10, 'helicopter':12}
And I also have a target value... say 120.
I am trying to find all possible results of the equation:
a*units['trooper'] + b*units['tank'] + c*units['helicopter'] = 120
So the result would look something like:
60*trooper
55*trooper + 1*tank
54*trooper + 1*helicopter
And so on with all possible combinations of the N keys in the dict...
How can I go about building this ?
Searching for solutions to these kinds of problems is easiest if you know what they are called. Google for Diophantine equations.
In the Python world, you can use the Sympy package which includes a Diophantine equation solver. That package makes short work of your problem:
from sympy import symbols
from sympy.solvers.diophantine import diop_solve
trooper, tank, helicopter = symbols('trooper tank helicopter', integer=True)
print diop_solve(2*trooper + 10*tank + 12*helicopter - 120)
It outputs:
(5*t - trooper + 60, -6*t + trooper - 60, trooper)
You can also search for "ways to make change" which is another way of expressing the problem. A related problem is called called The Knapsack Problem and it is famously difficult to solve. The math behind solving general systems of linear Diophantine equations is a bit involved. Here are some resources:
http://www.math.udel.edu/~lazebnik/papers/dior1.pdf
http://www.dcc.fc.up.pt/~apt/onlinepapers/epia97_final.pdf
https://en.wikipedia.org/wiki/Diophantine_equation#System_of_linear_Diophantine_equations
http://www.math.utah.edu/~carlson/hsp2004/PythonShortCourse.pdf
Something like this would work for small values of target value:
units = {'trooper':2, 'tank':10, 'helicopter':12}
total = 120
for i in range(int(total/units['helicopter'])):
for j in range(int(total/units['tank'])):
if (total-units['helicopter']*i-units['tank']*j)%2==0 and (total-units['helicopter']*i-units['tank']*j)>0:
print ((total-units['helicopter']*i-units['tank']*j)/2,j,i)

Categories

Resources