In order to calculate derivatives and other expressions I used the sympy package and said that T = sy.Symbol('T') now that I have calculated the right expression:
E= -T**2*F_deriv_T(T,rho)
where
def F_deriv_rho(T,rho):
ret = 0
for n in range(5):
for m in range(4):
inner= c[n,m]*g_rho_deriv_rho_np*g_T_np
ret += inner
return ret
that looks like this:
F_deriv_rho: [0.0 7.76971e-5*T 0.0001553942*T**2*rho
T*(-5.14488e-5*log(rho) - 5.14488e-5)*log(T) + T*(1.22574e-5*log(rho)+1.22574e-5)*log(T) + T*(1.89488e-5*log(rho) + 1.89488e-5)*log(T) + T(2.29441e-5*log(rho) + 2.29441e-5)*log(T) + T*(7.49956e-5*log(rho) + 7.49956e-5)*log(T)
T**2*(-0.0001028976*rho*log(rho) - 5.14488e-5*rho)*log(T) + T**2*(2.45148e-5*rho*log(rho) + 1.22574e-5*rho)*log(T) + T**2*(3.78976e-5*rho*log(rho) + 1.89488e-5*rho)*log(T) + T**2*(4.58882e-5*rho*log(rho) + 2.29441e-5*rho)*log(T) + T**2*(0.0001499912*rho*log(rho) + 7.49956e 5*rho)*log(T)]
with python I would like to change T (and rho) as a symbol to a value. How could I do that?
So, I would like to create 10 numbers like T_def = np.arange(2000, 10000, 800)and exchange all my sy.symbol(T) by iterating through the 10 values I created in the array.
Thanks for your help
I have found the solution according to this post:
How to substitute multiple symbols in an expression in sympy?
by usings "subs":
>>> from sympy import Symbol
>>> x, y = Symbol('x y')
>>> f = x + y
>>> f.subs({x:10, y: 20})
>>> f
30
There's more for this kinda thing here: http://docs.sympy.org/latest/tutorial/basic_operations.html
EDIT: A faster way would be by using "lamdify" as suggested by #Bjoern Dahlgren
Related
Is there a way to use sympy to find/replace all standalone integers (that aren't exponents) to 1.
For example, converting the following:
F(x) = (2/x^2) + (3/x^3) + 4
To:
F(x) = (1/x^2) + (1/x^3) + 1
I've searched extensively on stackoverflow for sympy expression.match/replace/find solutions, and have tried using a Wildcard symbol to find and replace all numbers in the expression but I keep running into the issue of matching and replacing the exponents (2 and 3 in this example) as well as they are also considered numbers.
Is there a simple (pythonic) way to achieve the above?
Thanks!
setdefault used with replace is a nice way to go. The single expression below has 3 steps:
mask off powers and record
change Rationals to 1 (to handle integers in numer or denom)
restore powers
>>> from sympy.abc import x
>>> from sympy import Dummy
>>> eq = (2/x**2) + (3/x**3) + 4 + 1/x/8
>>> reps = {}
>>> eq = eq.replace(lambda x: x.is_Pow, lambda x: reps.setdefault(x, Dummy())
).replace(lambda x: x.is_Rational, lambda x: 1
).xreplace({v:k for k,v in reps.items()})
1 + 1/x + 1/x**2 + 1/x**3
You can write a function that will recurse into your expression. For any expression expr, expr.args will give you the components of that expression. expr.is_constant() will tell you if it's a constant. expr.is_Pow will tell you if it's an exponential expression, so you can choose not to drill down into these expressions.
import sympy
def get_constants(expr):
c = set()
for x in expr.args:
if x.is_constant(): c |= {x}
if not x.is_Pow:
c |= get_constants(x)
return c
Now, you can get all the constants in said expression, and replace each of these constants using expr.replace().
def replace_constants(expr, repl):
for const in get_constants(expr):
expr = expr.replace(const, repl)
return expr
With your example expression, we get:
x = sympy.symbols('x')
F = 2/x**2 + 3/x**3 + 4
G = replace_constants(F, 1)
print(F) # 4 + 2/x**2 + 3/x**3
print(G) # 1 + x**(-2) + x**(-3)
Basically I have [5x5][5x1]=[0] and would like to have the symbolic expression of the solution.
Here is my code.
from sympy import symbols, solve
gm1, gm2, gm4 = symbols(['gm1', 'gm2', 'gm4'])
gds1, gds2, gds3, gds4, gds5 = symbols(['gds1', 'gds2', 'gds3', 'gds4', 'gds5'])
s = symbols(['s'])
Cd, CF , Cin, Ct = symbols(['Cd', 'CF', 'Cin', 'Ct'])
K = symbols(['K'])
vb, vc, ve, vout, iin = symbols(['vb', 'vc', 've', 'vout', 'iin'])
sol = solve([-(gds1+gds3+(s*Cd))*vb + (gm1+gds1)*ve + -gm1*vout, \
-gm4*vb + (gds4-gds2-(s*Cin)-(s*CF))*vc + (gds2+gm2)*ve + s*CF*vout + iin, \
gds1*vb + gds2*vc + (-(s*Ct)-gds5-gds1-gm1-gm2-gds2)*ve + gm1*vout, \
K*vc + vout], [vout])
print(sol)
but, I got this error
TypeError: can't multiply sequence by non-int of type 'Symbol'
From here, symbolic multiplication seems working just fine.
I am not sure whether I describe my problem in a way that does not comply with Sympy or something else.
What did I miss here?
The problem is in the assignment of the single symbols s and K. If instead you do:
s, K = symbols(['s', 'K'])
Or:
s = symbols('s')
K = symbols('K')
Whether you get the right answer or not is another matter :)
When you pass a list to symbols you get a list back. You can unpack that like [s] = symbols(['s']) or you can just pass a string of space or comma separated strings like x, y = symbols('x y') or x, y = symbols(','.join(['x', 'y']).
If you select manual=True you will get a solution vout=K*vc which sets the 4th equation to 0. But that was almost obvious, right? And you didn't need the other 3 equations to tell you that. So go ahead and pick up to 3 other variables for which you want to solve. There are lots of possibilities:
>>> from sympy.functions.combinatorial.numbers import nC
>>> allsym = Tuple(*eqs).free_symbols
>>> nfree = len(allsym) - 1 # always take vout
>>> print(nC(nfree, 3)) # want 3 others
816
For example, selecting (vout, gds4, gm1, gds5) gives a solution of
[{gds4: (CF*K*s*vc + CF*s*vc + Cin*s*vc + gds2*vc -
gds2*ve - gm2*ve + gm4*vb - iin)/vc,
gm1: (Cd*s*vb + gds1*vb - gds1*ve + gds3*vb)/(K*vc + ve),
gds5: -(Cd*s*vb + Ct*s*ve - gds2*vc + gds2*ve + gds3*vb + gm2*ve)/ve,
vout: -K*vc}]
In sympy (python) it seems that, by default, terms in univarate polynomials are ordered according to decreasing degrees: highest degree first, then second to highest, and so on. So, for example, a polynomial like
x + 1 + x^3 + 3x^6
will be printed out as 3x^6 + x^3 + x + 1.
I would like to reverse this order of polynomial terms in sympy to be increasing in the degrees. For the same example, the print-out should read 1 + x + x^3 + 3x^6. A solution that globally changes some parameter in program preamble is preferred but other options are also welcome.
Here is an MWE to play around with. It is different from the actual program I am working with. One part of the actual program (not the MWE) is printing out a list of recursively defined polynomials, e.g., P_n(x) = P_(n-1)(x) + a_n * x^n. It is easier for me to compare them when they are ordered by increasing degree. This is the motivation to change the order; doing it globally would probably just keep the code more readable (aesthetically pleasing). But the MWE is just for the same simple polynomial given in example above.
import sympy as sym
from sympy import *
x = sym.Symbol('x')
polynomial = x + 1 + x**3 + 3*x**6
print(polynomial)
Output of MWE:
>>> 3*x**6 + x**3 + x + 1
Desired output for MWE:
>>> 1 + x + x**3 + 3*x**6
You can get the leading term using sympy.polys.polytools.LT:
LT(3x ** 6 + x ** 3 + x + 1) == 3x**6
So at least you can churn out terms recursively and print it in your own way.
Unfortunately I’ve been trying to find some way to print the terms in some fix order for a long while and find no solution better than this
It's seems that there isn't an explicit way to do that and I found this approach to the problem:
to modify the print-representation of the object you can subclass its type and override the corresponding printing method (for LaTeX, MathML, ...) see documentation.
In this case _sympystr is used to "generates readable representations of SymPy expressions."
Here a basic implementation:
from sympy import Poly, symbols, latex
class UPoly(Poly):
"""Modified univariative polynomial"""
def _sympystr(self, printer) -> str:
"""increasing order of powers"""
if self.is_multivariate: # or: not self.is_univariate
raise Exception('Error, Polynomial is not univariative')
x = next(iter(expr.free_symbols))
poly_print = ""
for deg, coef in sorted(self.terms()):
term = coef * x**deg[0]
if coef.is_negative:
term = -term # fix sign
poly_print += " - "
else:
poly_print += " + "
poly_print += printer._print(term)
return poly_print.lstrip(" +-")
def _latex(self, printer):
return latex(self._sympystr(printer)) # keep the order
x = symbols('x')
expr = 2*x + 6 - x**5
up = UPoly(expr)
print(up)
#6 + 2*x - x**5
print(latex(up))
#6 + 2 x - x^{5}
I have a sympy expression I want to put numerical values in after differentiating it. The variables I want to replace are all the x[i], y[i] and R_abs[i] in the last expression and are numpy arrays a la
rx=np.array([-0.357, -0.742, -1.078, 0.206])
But trying subs or replace either doesn't do anything or raises the error that Symbols dont allow indexation for for example e1.subs(x[1],rx[0]). I pretty much went through every iteration I could think of to no avail.
import sympy as sp
r0,ge_x,ge_y,bx,by = sp.symbols('r0,ge_x,ge_y,bx,by', real=True) #Main symbols
i,x,y,R_abs = sp.symbols('i,x,y,R_abs', real=True) #Helper symbols
n=4
s2=sp.Sum((bx+r0*sp.Indexed('x',i)/sp.Indexed('R_abs',i)+ge_x*sp.Indexed('x',i)+ge_y*sp.Indexed('y',i)-sp.Indexed('x',i))**2+(by+r0*sp.Indexed('y',i)/sp.Indexed('R_abs',i)-ge_x*sp.Indexed('y',i)+ge_y*sp.Indexed('x',i)-sp.Indexed('y',i))**2,(i,1,n))
e1=sp.Eq(sp.diff(s2,bx).doit(),0)
With e1 then being
Eq(8*bx + 2*ge_x*x[1] + 2*ge_x*x[2] + 2*ge_x*x[3] + 2*ge_x*x[4] + 2*ge_y*y[1] + 2*ge_y*y[2] + 2*ge_y*y[3] + 2*ge_y*y[4] + 2*r0*x[4]/R_abs[4] + 2*r0*x[3]/R_abs[3] + 2*r0*x[2]/R_abs[2] + 2*r0*x[1]/R_abs[1] - 2*x[1] - 2*x[2] - 2*x[3] - 2*x[4], 0)
In here I would like to replace all the x, y, and R_abs with their numerical values.
I've always struggled with indexing in SymPy. Turns out, making Function instances are way easier than indexing instances of Symbol. It also makes notation simpler.
Also note that by using strings in your expression, I think SymPy makes its own symbols with those same string names but they can't be accessed with yours since your symbols are different. At least that's what happens sometimes to me.
Here is a working sample:
import sympy as sp
r0, ge_x, ge_y, bx, by = sp.symbols("r0 ge_x ge_y bx by", real=True) # main symbols
# define functions that will take the role of indexed symbols
x = sp.Function("x")
y = sp.Function("y")
R_abs = sp.Function("R_abs")
i = sp.Symbol("i", positive=True, integer=True)
n = 4
s2 = sp.Sum((bx + r0 * x(i) / R_abs(i) + ge_x * x(i) + ge_y * y(i) - x(i)) ** 2 +
(by + r0 * y(i) / R_abs(i) - ge_x * y(i) + ge_y * x(i) - y(i)) ** 2, (i, 1, n))
s2_prime = sp.diff(s2, bx).doit().simplify()
print(s2_prime)
# whatever lists you want. Can even be an instance of `np.ndarray`
# note that you summed from 1 to n so the 0th element will not be used
x_array = [0, 1, 2, 3, 4]
y_array = [4, 3, 2, 1, 0]
R_abs_array = [-10, 10, 5, 4, 3]
# define a function to access these array elements
x_function = lambda index: x_array[index]
y_function = lambda index: y_array[index]
R_abs_function = lambda index: R_abs_array[index]
# no idea why subs does not work and you MUST keep the same name for the variable.
# you can't have for example `evaluated_s2_prime = ...`.
# Probably something to do with forcing sp to remove references to `x`?
s2_prime = s2_prime.replace(x, x_function).replace(y, y_function).replace(R_abs, R_abs_function)
print(s2_prime)
Producing:
8*bx + 2*ge_x*x(1) + 2*ge_x*x(2) + 2*ge_x*x(3) + 2*ge_x*x(4) + 2*ge_y*y(1) + 2*ge_y*y(2) + 2*ge_y*y(3) + 2*ge_y*y(4) + 2*r0*x(4)/R_abs(4) + 2*r0*x(3)/R_abs(3) + 2*r0*x(2)/R_abs(2) + 2*r0*x(1)/R_abs(1) - 2*x(1) - 2*x(2) - 2*x(3) - 2*x(4)
8*bx + 20*ge_x + 12*ge_y + 31*r0/6 - 20
Using sympy, I need to replace all occurrence of exp(C+anything) with C*exp(anything). Because exp(C) is constant, I just write at as C.
I can do this for one occurrence of exp in the expression. But do not how to do it if there are than one instance.
For example, for one instance, as in x+exp(C_0+3*x)+3*y, I need to change it to x+C_0*exp(3*x)+3*y
For one instance, this seems to work after some trial and error
from sympy import *
x,y,C_0 = symbols('x y C_0')
expr=x+exp(C_0+3*x)+3*y
#first check if exp is in the expression
if any([isinstance(a, exp) for a in preorder_traversal(expr)]):
p_1=Wild('p1');p_2=Wild('p_2');p_3=Wild('p_3')
r=(p_1+exp(C_0+p_2)+p_3).matches(expr)
expr.subs(exp(C_0+r[p_2]),C_0*exp(r[p_2]))
Which gives
C_0*exp(3*x) + x + 3*y
But what about something like x+exp(C_0+3*x)+3*y+exp(C_0+30*x+y) which I need to change to x+C_0*exp(3*x)+3*y+C_0*exp(30*x+y) I can't make special pattern match for each possible case. I need a way to change all occurrences
In Mathematica, I do the above as follows
expr = x + Exp[c + 3*x]*3*y + 3*y + Exp[c + 30*x + y]
expr /. Exp[c + any_] :> (c Exp[any])
Which gives
I actually prefer to tell Python just to change exp(C+anything) to C*exp(anything) without having to give pattern for the overall expression, since that can change in many way.
I am sure the above is also possible in python/sympy. Any hints how to do it?
I would look for function exp inside of the expression, check whether its argument is Add, and then whether C_0 is among the arguments of Add. Then build a thing to replace exp with. Consider the following:
from sympy import *
x, y, C_0 = symbols('x y C_0')
expr = x + exp(C_0+3*x) + 3*y + exp(y+C_0+30*x) - exp(x+y-C_0) + exp(x*y)
exp_sum = [(a, a.args[0].args) for a in preorder_traversal(expr) if a.func == exp and a.args[0].func == Add]
exp_sum = [p for p in exp_sum if C_0 in p[1]]
new_exp = [C_0*exp(Add(*[x for x in p[1] if x != C_0])) for p in exp_sum]
for (old, new) in zip(exp_sum, new_exp):
expr = expr.subs(old[0], new)
Initially, exp_sum contains all parts of the form exp(Add(...)). After that it's filtered down to sums containing C_0. New exponentials are formed by taking all summands that are not C_0, adding them, applying exp and multiplying by C_0. Then substitution happens.
To clarify the process, here is what exp_sum is in the above example: a list of tuples (exponential and the summands inside):
[(exp(C_0 + 3*x), (C_0, 3*x)), (exp(C_0 + 30*x + y), (C_0, y, 30*x))]
And this is new_exp
[C_0*exp(3*x), C_0*exp(30*x + y)]
Finally, expr at the end:
C_0*exp(3*x) + C_0*exp(30*x + y) + x + 3*y + exp(x*y) - exp(-C_0 + x + y)
Notice that exp(-C_0...) is not affected by the change; it's not a part of the pattern.