Using sympy to rearrange an expression - python

I am attempting to solve for a variable (T_p) in terms of another (T_i) using sympy. However all that is returned after running is empty square brackets i.e [].
My current code is as follows:
from sympy import *
T_i, T_p = symbols('T_i T_p')
eq = Eq(1.32*(T_i - T_p)**1.25 + 58.5*T_i, 3774)
sol = (solve(eq, T_p))
print(sol)
I am unsure what is wrong as it has worked for other equations. Any help would be appreciated.
Could it be that the solve function doesn't like fractional powers? If so, is there a similar function that does?

Related

I have a long expression which I want to simplify but assuming that an equation holds

In Mathematica, you can use the function FullSimplify[expression,assumptions] to simplify expressions using assumptions. For instance, if I do this:
FullSimplify[x^2-y^2,x^2-y^2==1],
then the result will be 1 because that's the 'simplest expression that is equivalent to the function I gave the software.
Now I need to do the same with Python, but I don't know how to do that. I have seen the documentation about the command sympy.refine on this page:
https://docs.sympy.org/latest/modules/assumptions/refine.html
However, I haven't been able to use equalities as assumptions. It doesn't seem possible to assume things like that with the Q function.
I have tried to do something like this:
import sympy as sp
x,y=sp.symbols('x y')
sp.refine(x**2-y**2,x==y)
However, this gives me the following error: ValueError: Inconsistent assumptions
Does someone have any ideas about this? Thank you.
Without some scope for what kind of expressions and assumptions you want to work with this is probably an unsolvable problem so I'll make some assumptions.
If you want to simplify a polynomial expression based on some other polynomial expression(s) being zero then you can do this in sympy using ratsimpmodprime:
In [1]: x, y = symbols('x, y')
In [2]: assumptions = [x**2 + y**2 - 1]
In [3]: expression = x**2 + y**2
In [4]: ratsimpmodprime(expression, assumptions)
Out[4]: 1
https://docs.sympy.org/latest/modules/simplify/simplify.html#ratsimpmodprime
I tried two approaches to the problem.
Assume that x - y = 0. This was the only way I could find to express the assumption that you want to make. Unfortunately, it doesn't seem to be smart enough to notice that this assumption allows it to substitute x for y.
print("refine:", sp.refine(x**2-y**2,Q.zero(x-y)))
This just returns the original expression.
Ask sympy to substitute the expression. This isn't as automatic - you're asking it to do the substitution instead of giving it the option of doing the substitution, but it does work for this toy example.
expr = (x**2-y**2)
print("substitution:", expr.subs(x**2-y**2, 1))
prints 1.

Replacing numbers with parameters in sympy

I have some SymPy expressions of the form: 2*x1**2+7*cos(8*x2)+2*Pi (mine are longer and more complicated, but this should be enough for my question). How can I turn all the numbers appearing in this expression into parameters, something like this: a*x1**2+b*cos(c*x2)+d. Basically, I have a program which is able to give me an approximate function able to fit some data, but the parameters are integers or some well known numbers, such as pi or e (this is the first expression I provided). Then, I want to take that expression and fine tune these numbers (using gradient descent), such that to obtain the actual parameters (one can assume that the functional form is right, just the parameters need to be adjusted). For example, in the end, the right equation could be: 2.87*x1**2+6.95*cos(8.05*x2)+6.27. Is there a way to do this? Thank you!
It's a little tricky because you say "all numbers" but you are ignoring exponents. In your example you are only replacing numerical factors in a term with new symbols. To do that (and to get you on your way with a possible solution) try using replace, telling it you are looking for a Mul and then telling it what you want to do with the Mul when you have it:
from sympy import *
from sympy.abc import x,y
eq=2*x**2+7*cos(8*y)+2*pi
def nfact2dum(m):
assert m.is_Mul
nonnum = sift(m.args, lambda i:i.is_number, binary=True)[1]
return Mul(*([Dummy()] + nonnum))
deq = eq.replace(
lambda x:x.is_Mul,
lambda x: nfact2dum(x))
print(
deq.subs(list(zip(deq.atoms(Dummy),numbered_symbols('c')))))
output: c0*x**2 + c2*cos(c1*y) + c3

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.

Using Python's Regular Expression to Insert Symbol Between Certain Characters

I am making a math program that allows the user to input an equation and the program will solve it. I am trying to make it as user friendly as possible. I want the user to be able to easily type an equation in without having to worry about adding the multiplication symbol between every instance of multiplication.
Here is an example:
User input: y=xy+yz Program output: y=x*y+y*z
I have been able to accomplish this easily using Python's re module as follows:
equation = "y=xy+yz"
equation = re.sub(r"([xyzuvet])([xyzuvet])",r"\1*\2", equation) # x,y,z,u,v,e, and t and variables and constants the user can use in their equation.
equation = re.sub(r"([xyzuvet])([xyzuvet])",r"\1*\2", equation) # Must run twice in the event the equation looks something like y=xyzxyz
However I run into a problem when I introduce a special function such as y=yexp(x). When I run the code above, I will get an output of y=y*e*xp(x).
I later updated my code to account for pi:
equation = re.sub(r"([xyzuve]|pi)([xyzuve]|pi)",r"\1*\2", equation)
equation = re.sub(r"([xyzuve]|pi)([xyzuve]|pi)",r"\1*\2", equation)
I was thinking I could use a similar approach from above to match exp and prevent it from adding a * between the 'e' and 'x' as follows:
equation = re.sub(r"([xyzuve]|pi|exp)([xyzuve]|pi|exp)",r"\1*\2", equation)
equation = re.sub(r"([xyzuve]|pi|exp)([xyzuve]|pi|exp)",r"\1*\2", equation)
I thougt by adding exp in the same way I did pi, it would work; but unfortunately it doesn't work. Is there a way to treat exp and other functions that also contain x,y,z,u,v,t, and e as a whole?
Here are some examples of what I want an input to look like:
In: y=eexp(xyz) out: y=e*exp(x*y*z)
In: y=pifrexp(yt) out: y=pi*frexp(y*t)
In: y=sin(x)exp(y) out:y=sin(x)*exp(y)
This seems to produce what you want:
equation = re.sub(r"([)xyzuvet]|pi|exp|frexp)([xyzuvet]|pi|exp|frexp)\b",r"\1*\2", equation)
equation = re.sub(r"([)xyzuvet]|pi|exp|frexp)([xyzuvet]|pi|exp|frexp)\b",r"\1*\2", equation)
For example:
>>> import re
>>> eqns = ('y=eexp(xyz)', 'y=pifrexp(yt)', 'y=sin(x)exp(y)')
>>> for equation in eqns:
... equation = re.sub(r"([)xyzuvet]|pi|exp|frexp)([xyzuvet]|pi|exp|frexp)\b",r"\1*\2", equation)
... equation = re.sub(r"([)xyzuvet]|pi|exp|frexp)([xyzuvet]|pi|exp|frexp)\b",r"\1*\2", equation)
... print equation
...
y=e*exp(x*y*z)
y=pi*frexp(y*t)
y=sin(x)*exp(y)
You can use look arounds to as
(?<=[xyzuvtf])(?=[xyzuvtf])|(?=exp)|(?<=pi)
Regex Demo
This regex based on lookarounds works for all your test cases:
(?!^)(?=(?<!fr)(?:fr)?exp|sin|pi|(?<=[xtyzuv]|e(?!xp))[etxyzuv])
RegEx Demo

Sympy library solve to an unknown variable

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.

Categories

Resources