sympy : expression simplification - python

I begin with sympy python lib.
If, I have this expression
from sympy.abc import a,b,c,p,q
e = p * ( a + b ) + q * ( a + c )
how I can use a,b,c as factor ? like
a(p+q) + b*p + c*q

from sympy.abc import a,b,c,p,q
from sympy import collect, expand
e = p * ( a + b ) + q * ( a + c )
print e
print expand(e)
print collect(expand(e),a)

collect is indeed the function you want. You can pass multiple symbols as the collection variable to collect them all. And as you noticed, collect will not expand your expression first, so if you want that, you have to do it yourself with expand.
In [15]: collect(e.expand(), [a, b, c])
Out[15]: a⋅(p + q) + b⋅p + c⋅q

Related

Solving system of nonlinear (and nonpolynomial) equations

I would like to use python/sympy to solve simple systems of equations coming from impedance calculations in electronics.
In such calculations, due to the "parallel impedance" formula, one often has to deal with expressions of the form:
par(x,y) := (x*y)/(x+y)
Now I have tried with the following code:
from sympy import *
def par(var1,var2):
return (var1 * var2)/(var1+var2)
A = Symbol('A')
B = Symbol('B')
C = Symbol('C')
D = Symbol('D')
E = Symbol('E')
eq1 = A + par(B+50 , (C+ par(D, (E+50)) )) - 50
eq2 = B + par(A+50 , (C+ par(D , (E+50)) )) - 50
eq3 = E + par(D+50, (C+ par(A+50, B+50)) ) - 50
thus defining a system of three equations in five variables {A,B,C,D,E}, but then running
solve([eq1,eq2,eq3], A, B,C,D,E)
the computations just does not terminate.
Do you have any suggestions on how I could approach these type of equations?
Basically polynomials with division by polynomials, with solutions in the complex numbers.
Taking the suggestion of Oscar and focussing on A, B and C you can get a solution for them in terms of D and E:
>>> solve((eq1, eq2, eq3), A, B, C)[0] # one solution
(
50*(D + E)*(D + E + 50)/(3*D**2 - 2*D*E + 150*D - 3*E**2 - 50*E + 5000),
50*(D + E)*(D + E + 50)/(3*D**2 - 2*D*E + 150*D - 3*E**2 - 50*E + 5000),
(-3*D**3*E + 50*D**3 + 2*D**2*E**2 - 500*D**2*E + 10000*D**2 + 3*D*E**3 + 50*D*E**2 - 25000*D*E + 500000*D + 200*E**3 - 5000*E**2 - 500000*E + 12500000)/(3*D**3 + D**2*E + 150*D**2 - 5*D*E**2 + 100*D*E + 5000*D - 3*E**3 - 50*E**2 + 5000*E))
Notice that the solution for A and B is the same (consistent with the symmetry of the first two equations wrt A and B).
>>> sol = Dict(*zip((A,B,C),_))
>>> sol[A] = sol[B]
True
In this form, you can directly substitute values for D and E:
>>> sol.subs({D:1, E:S.Half})
{A: 1030/1367, B: 1030/1367, C: 2265971/1367}
You can also see what relationships between D and E are forbidden by solving for when any of the denominators are 0:
>>> from sympy.solvers.solvers import denoms
>>> set([j.simplify() for i in denoms(sol) for j in solve(i,D)])
{-E, E/3 - sqrt(10*E**2 - 9375)/3 - 25, E/3 + sqrt(10*E**2 - 9375)/3 - 25}
You could also try the Z3 library:
from z3 import Reals, Solver, sat, set_option
def par(var1, var2):
return (var1 * var2) / (var1 + var2)
vars = Reals('A B C D E')
A, B, C, D, E = vars
set_option(rational_to_decimal=True, precision=30)
s = Solver()
s.add(A + par(B + 50, (C + par(D, (E + 50)))) == 50)
s.add(B + par(A + 50, (C + par(D, (E + 50)))) == 50)
s.add(E + par(D + 50, (C + par(A + 50, B + 50))) == 50)
if s.check() == sat:
m = s.model()
print(m)
I get following output:
[D = 0.502507819412956050111927878839?,
C = 0.125,
E = 50.188198722936229689352204927638?,
B = -50.625,
A = -50.625]
The question mark at the end of D's and E's values means they have been approximated.
If you then try the values for A, B and C into the original code, sympy gives two exact expressions:
[{A: -405/8,
B: -405/8,
C: 1/8,
D: -31857/1292 + 5*sqrt(676050154)/5168,
E: 443/1304 + 5*sqrt(676050154)/2608},
{A: -405/8,
B: -405/8,
C: 1/8,
D: -5*sqrt(676050154)/5168 - 31857/1292,
E: 443/1304 - 5*sqrt(676050154)/2608}]

Why doesn't SymPy simplify the expression?

I am just looking at the Python module SymPy and try, as a simple (useless) example the fit of a function f(x) by a function set g_i(x) in a given interval.
import sympy as sym
def functionFit(f, funcset, interval):
N = len(funcset) - 1
A = sym.zeros(N+1, N+1)
b = sym.zeros(N+1, 1)
x = sym.Symbol('x')
for i in range(N+1):
for j in range(i, N+1):
A[i,j] = sym.integrate(funcset[i]*funcset[j],
(x, interval[0], interval[1]))
A[j,i] = A[i,j]
b[i,0] = sym.integrate(funcset[i]*f, (x, interval[0], interval[1]))
c = A.LUsolve(b)
u = 0
for i in range(len(funcset)):
u += c[i,0]*funcset[i]
return u, c
x = sym.Symbol('x')
f = 10*sym.cos(x)+3*sym.sin(x)
fooset=(sym.sin(x), sym.cos(x))
interval = (1,2)
print("function to approximate:", f)
print("Basic functions:")
for foo in fooset:
print(" - ", foo)
u,c = functionFit(f, fooset, interval)
print()
print("simplified u:")
print(sym.simplify(u))
print()
print("simplified c:")
print(sym.simplify(c))
The result is the fit function u(x), to be returned, together with the coefficients by functionFit.
In my case
f(x) = 10 * sym.cos(x) + 3 * sym.sin(x)
and I want to fit it according to a linear combination of sin(x), cos(x).
So the coefficients should be 3 and 10.
The result is OK, but for u(x) I get
u(x) = (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2))) :
Function to approximate: 3*sin(x) + 10*cos(x)
Basic functions:
- sin(x)
- cos(x)
Simplified u: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
Simplified c: Matrix([[3], [10]])
which is indeed the same as 10 * cos(x) + 3 * sin(x).
However I wonder why it is not simplified to that expression. I tried several simplifying function available, but none of it gives the expected result.
Is there something wrong in my code or are my expectations to high?
Don't know if this is a solution for you, but I'd simply use the .evalf method of every Sympy expression
In [26]: u.simplify()
Out[26]: (12*sin(2)**2*sin(4)*sin(x) + 3*sin(8)*sin(x) + 12*sin(2)*sin(x) + 40*sin(2)**2*sin(4)*cos(x) + 10*sin(8)*cos(x) + 40*sin(2)*cos(x))/(2*(sin(4) + 2*sin(2)))
In [27]: u.evalf()
Out[27]: 3.0*sin(x) + 10.0*cos(x)
In [28]:

Remove mixed-variable terms in SymPy series expansion

Consider two functions of SymPy symbols e and i:
from sympy import Symbol, expand, Order
i = Symbol('i')
e = Symbol('e')
f = (i**3 + i**2 + i + 1)
g = (e**3 + e**2 + e + 1)
z = expand(f*g)
This will produce
z = e**3*i**3 + e**3*i**2 + e**3*i + e**3 + e**2*i**3 + e**2*i**2 + e**2*i + e**2 + e*i**3 + e*i**2 + e*i + e + i**3 + i**2 + i + 1
However, assume that e and i are both small and we can neglect both terms that are order three or higher. Using Sympy’s series tool or simply adding an O-notation Order class can handle this:
In : z = expand(f*g + Order(i**3) + Order(e**3))
Out: 1 + i + i**2 + e + e*i + e*i**2 + e**2 + e**2*i + e**2*i**2 + O(i**3) + O(e**3)
Looks great. However, I am still left with mixed terms e**2 * i**2. Individual variables in these terms are less than the desired cut-off so SymPy keeps them. However, mathematically small²·small² = small⁴. Likewise, e·i² = small·small² = small³.
At least for my purposes, I want these mixed terms dropped. Adding a mixed Order does not produce the desired result (it seems to ignore the first two orders).
In : expand(f*g + Order(i**3) + Order(e**3) + Order((i**2)*(e**2)))
Out: 1 + i + i**2 + i**3 + e + e*i + e*i**2 + e*i**3 + e**2 + e**2*i + e**3 + e**3*i + O(e**2*i**2, e, i)
Question: Does SymPy have an easy system to quickly remove the n-th order terms, as well as terms that are (e^a)·(i^b) where a+b > n?
Messy Solution: I have found a way to solve this, but it is messy and potentially not general.
z = expand(f*g + Order((e**2)*i) + Order(e*(i**2)))
zz = expand(z.removeO() + Order(e**3) + Order(i**3))
produces
zz = 1 + i + i**2 + e + e*i + e**2 + O(i**3) + O(e**3)
which is exactly what I want. So to specify my question: Is there a way to do this in one step that can be generalized to any n? Also, my solution loses the big-O notation that indicates mixed-terms were lost. This is not needed but would be nice.
As you have a dual limit, you must specify both infinitesimal variables (e and i) in all Order objects, even if they don’t appear in the first argument.
The reason for this is that Order(expr) only automatically chooses those symbols as infinitesimal that actually appear in the expr and thus, e.g., O(e) is only for the limit e→0.
Now, Order objects with different limits don’t mix well, e.g.:
O(e*i)+O(e) == O(e*i) != O(e)+O(e*i) == O(e) # True
This leads to a mess where results depend on the order of addition, which is a good indicator that this is something to avoid.
This can be avoided by explicitly specifying the infinitesimal symbols (as addition arguments of Order), e.g.:
O(e*i)+O(e,e,i) == O(e,e,i)+O(e*i) == O(e,e,i) # True
I haven’t found a way to avoid going through all combinations of e and i manually, but this can be done by a simple iteration:
orders = sum( Order(e**a*i**(n-a),e,i) for a in range(n+1) )
expand(f*g+orders)
# 1 + i + i**2 + e + e*i + e**2 + O(e**2*i, e, i) + O(e*i**2, e, i) + O(i**3, e, i) + O(e**3, e, i)
Without using Order you might try something simple like this:
>>> eq = expand(f*g) # as you defined
>>> def total_degree(e):
... x = Dummy()
... free = e.free_symbols
... if not free: return S.Zero
... for f in free:
... e = e.subs(f, x)
... return degree(e)
>>> eq.replace(lambda x: total_degree(x) > 2, lambda x: S.Zero)
e**2 + e*i + e + i**2 + i + 1
There is a way about it using Poly. I have made a function that keeps the O(...) term and another that does not (faster).
from sympy import Symbol, expand, Order, Poly
i = Symbol('i')
e = Symbol('e')
f = (i**3 + i**2 + i + 1)
g = (e**3 + e**2 + e + 1)
z = expand(f*g)
def neglect(expr, order=3):
z = Poly(expr)
# extract all terms and keep the lower order ones
d = z.as_dict()
d = {t: c for t,c in d.items() if sum(t) < order}
# Build resulting polynomial
return Poly(d, z.gens).as_expr()
def neglectO(expr, order=3):
# This one keeps O terms
z = Poly(expr)
# extract terms of higher "order"
d = z.as_dict()
large = {t: c for t,c in d.items() if sum(t) >= order}
for t in large: # Add each O(large monomial) to the expression
expr += Order(Poly({t:1},z.gens).as_expr(), *z.gens)
return expr
print(neglect(z))
print(neglectO(z))
This code prints the following:
e**2 + e*i + e + i**2 + i + 1
1 + i + i**2 + e + e*i + e**2 + O(e**2*i, e, i) + O(e*i**2, e, i) + O(i**3, e, i) + O(e**3, e, i)

how to nudge substitutions in sympy

i have the following where a, b, c, d are all sympy symbols
p = a + b + 2*c + d
q = a + b + c + d
i wanted to do this:
p = p.subs(a + b + c + d, q)
and wanted to get this:
p = q + c
but p remains unchanged.
what should i be doing to get to p = q + c?
the matching performed by subs() seems to be looking for strict ordering, and hence it didn't split up the '2*c' term.
should i be using replace() instead of subs().
EDIT:
code as follows:
import sympy
a, b, c, d = sympy.symbols('a,b,c,d')
p = a + b + 2*c + d
q = a + b + c + d
r = p.subs(a + b + c + d, q)
print r
EDIT #2
https://groups.google.com/forum/#!topic/sympy/b_Yv6s15Y0Q
my problem is similar to the groups.google link, just that in that case subs() do its job.
First a comment about your code: since you define q to be the sum a+b+c+d you will never see the change, even if it did work (but it doesn't). Something else that does work is the following:
>>> p = a + b + 2*c + d
>>> q = var('q')
>>> p.extract_additively(a+b+c+d) + q
c + q
There is also an extract_multiplicatively method.

Testing equivalence of mathematical expressions in Python

I have got two strings in Python,
A m * B s / (A m + C m)
and
C m * B s / (C m + A m)
that are both equivalent functions of the unordered set (A, C) and the unordered set (B). m and s indicate units that can be swapped among the same but not with another unit.
So far, I'm doing permutations of A, B, and C and testing them using eval and SymPy's == operator. This has multiple drawbacks:
for more complicated expressions, I have to generate a large number of permutations (in my case 8 nested for loops)
I need to define A, B, C as symbols, which is not optimal when I don't know which parameters I will have (so I have to generate all of them -> terribly inefficient and messing up my variable namespace)
Is there a pythonian way to test for this kind of equivalence? It should work an arbitrary expressions.
Here is a simplified approach based on my previous answer.
The idea is that if two expressions are equivalent under permutations, the permutation carrying one to the other must map the ith symbol in the first string (ordered by index of first occurrence) to the ith symbol in the second string (again ordered by index of first occurrence). This principle can be used to construct a permutation, apply it to the first string and then check for equality with the second string - if they are equal they are equivalent, otherwise they are not.
Here is one possible implementation:
import re
# Unique-ify list, preserving order
def uniquify(l):
return reduce(lambda s, e: s + ([] if e in s else [e]), l, [])
# Replace all keys in replacements with corresponding values in str
def replace_all(str, replacements):
for old, new in replacements.iteritems():
str = str.replace(old, new)
return str
class Expression:
units = ["m", "s"]
def __init__(self, exp):
self.exp = exp
# Returns a list of symbols in the expression that are preceded
# by the given unit, ordered by first appearance. Assumes the
# symbol and unit are separated by a space. For example:
# Expression("A m * B s / (A m + C m)").symbols_for_unit("m")
# returns ['A', 'C']
def symbols_for_unit(self, unit):
sym_re = re.compile("(.) %s" % unit)
symbols = sym_re.findall(self.exp)
return uniquify(symbols)
# Returns a string with all symbols that have units other than
# unit "muted", that is replaced with the empty string. Example:
# Expression("A m * B s / (A m + C m)").mute_symbols_for_other_units("m")
# returns "A m * s / (A m + C m)"
def mute_symbols_for_other_units(self, unit):
other_units = "".join(set(self.units) - set(unit))
return re.sub("(.) ([%s])" % "".join(other_units), " \g<2>", self.exp)
# Returns a string with all symbols that have the given unit
# replaced with tokens of the form $0, $1, ..., by order of their
# first appearance in the string, and all other symbols muted.
# For example:
# Expression("A m * B s / (A m + C m)").canonical_form("m")
# returns "$0 m * s / ($0 m + $1 m)"
def canonical_form(self, unit):
symbols = self.symbols_for_unit(unit)
muted_self = self.mute_symbols_for_other_units(unit)
for i, sym in enumerate(symbols):
muted_self = muted_self.replace("%s %s" % (sym, unit), "$%s %s" % (i, unit))
return muted_self
# Define a permutation, represented as a dictionary, according to
# the following rule: replace $i with the ith distinct symbol
# occurring in the expression with the given unit. For example:
# Expression("C m * B s / (C m + A m)").permutation("m")
# returns {'$0':'C', '$1':'A'}
def permutation(self, unit):
enum = enumerate(self.symbols_for_unit(unit))
return dict(("$%s" % i, sym) for i, sym in enum)
# Return a string produced from the expression by first converting it
# into canonical form, and then performing the replacements defined
# by the given permutation. For example:
# Expression("A m * B s / (A m + C m)").permute("m", {"$0":"C", "$1":"A"})
# returns "C m * s / (C m + A m)"
def permute(self, unit, permutation):
new_exp = self.canonical_form(unit)
return replace_all(new_exp, permutation)
# Test for equality under permutation and muting of all other symbols
# than the unit provided.
def eq_under_permutation(self, unit, other_exp):
muted_self = self.mute_symbols_for_other_units(unit)
other_permuted_str = other_exp.permute(unit, self.permutation(unit))
return muted_self == other_permuted_str
# Test for equality under permutation. This is done for each of
# the possible units using eq_under_permutation
def __eq__(self, other):
return all([self.eq_under_permutation(unit, other) for unit in self.units])
e1 = Expression("A m * B s / (A m + C m)")
e2 = Expression("C m * B s / (C m + A m)")
e3 = Expression("A s * B s / (A m + C m)")
f1 = Expression("A s * (B s + D s) / (A m + C m)")
f2 = Expression("A s * (D s + B s) / (C m + A m)")
f3 = Expression("D s")
print "e1 == e2: ", e1 == e2 # True
print "e1 == e3: ", e1 == e3 # False
print "e2 == e3: ", e2 == e3 # False
print "f1 == f2: ", f1 == f2 # True
print "f1 == f3: ", f1 == f3 # False
As you pointed out, this checks for string equivalence under permutations without any regard to mathematical equivalence, but it is half the battle. If you had a canonical form for mathematical expressions, you could use this approach on two expressions in canonical form. Perhaps one of sympy's Simplify could do the trick.
Instead of iterating over all possible permutations, assume one exists and attempt to construct it. I believe that done in the right way, failure of the algorithm would imply inexistence of the permutation.
Here is the outline of the idea applied to the expressions above:
let:
str1 = "A m * B s / (A m + C m)"
str2 = "C m * B s / (C m + A m)"
We're looking for a permutation of the set (A, C) that would render the expressions identical. Relabel A and C as X1 and X2 according to the order of their first appearance in str2, so:
X1 = C
X2 = A
because C appears before A in str2. Next, create the array Y such that y[i] is the ith symbol A or C in order of first appearance in str1. So:
Y[1] = A
Y[2] = C
Because A appears before C in str1.
Now construct str3 from str2 by replacing A and C with X1 and X2:
str3 = "X1 m * B s / (X1 m + X2 m)"
And then start substituting Xi for Y[i]. First, X1 becomes Y[1]=A:
str3_1 = "A m * Bs / (A m + X2 m)"
At this stage, compare str3_1 and str1 up to the first occurrence of any of the Xi's, in this case X2, so because these two strings are equal:
str3_1[:18] = "A m * B s / (A m + "
str1[:18] = "A m * B s / (A m + "
You have a chance of constructing the permutation. If they were unequal, you'd have proven no suitable permutation exists (because any permutation would have had to make at least that substitution) and could deduce inequivalence. But they are equal, so you proceed to the next step, substituting X2 for Y[2]=C:
str3_2 = "A m * B s / (A m + C m)"
And this is equal to str1, so you have your permutation (A->C, C->A) and have shown the equivalence of the expressions.
This is only a demonstration of the algorithm to a particular case, but it should generalize. Not sure what the lowest order you could get it down to is, but it should be quicker than the n! of generating all permutations on n variables.
If I understand the significance of the units correctly, they limit which variables may be swapped for which others by the permutations. So that A can be substituted with C in the above expressions because both have 'm' units, but not with B which has 's' units. You can handle this in the following way:
construct expressions str1_m and str2_m from str1 and str2 by removing all symbols that don't have m units, and then carry out the above algorithm for str1_m and str2_m. If construction fails, no permutation exists. If construction succeeds, keep that permutation (call it the m-permutation) and construct str1_s and str2_s from str1 and str2 by removing all symbols that don't have s units, then carry out the algorithm again for str1_s and str2_s. If construction fails, they are not equivalent. If it succeeds, the final permutation will be a combination of the m-permutation and the s-permutation (although you probably don't even need to construct it, you just care that it exists).
If you pass a string to SymPy's sympify() function, it will automatically create the Symbols for you (no need to define them all).
>>> from sympy import *
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> sympify("x**2 + cos(x)")
x**2 + cos(x)
>>> sympify("diff(x**2 + cos(x), x)")
2*x - sin(x)
I did it once, in one simulater of mathemathics estudies..
Well, in my case, i knew what were the variables that will be used.
So, i tested the result putting values inside the vars.
A = 10
B = 20
C = 30
m = Math.e
s = Math.pi
And so, we solve:
s1 = 'A m * B s / (A m + C m)'
s2 = 'C m * B s / (C m + A m)'
If s1 != s2, was proved there isn't equivalence
With this method is impossible say that two expressions are equivalent,
But you can say that both isn't equivalent
if s1 != s2:
print "Not equivalent"
else:
print "Try with another sample"
Well.. I hope that this can help you.
This, like all other answers to date is not a robust solution to the problem, but instead contains more helpful information for our future meticulous friend to solve it.
I provide a difficult example using Euler's Formula https://en.wikipedia.org/wiki/Euler%27s_formula
I am certain all other overflow answers to date will not succeed in my example.
I show that all the suggestions on sympy's website also fail on my example. (https://github.com/sympy/sympy/wiki/Faq)
#SOURCE FOR HELPERS: https://github.com/sympy/sympy/wiki/Faq
import sympy
import sympy.parsing.sympy_parser
ExampleExpressionString1 = 'exp( i*( (x0 - 1)*(x0 + 2) ) )'
ExampleExpressionSympy1 = sympy.parsing.sympy_parser.parse_expr(ExampleExpressionString1)
ExampleExpressionString2 = 'i*sin( (x0 - 1)*(x0 + 2) ) + cos( (x0 - 1)*(x0 + 2) )'
ExampleExpressionSympy2 = sympy.parsing.sympy_parser.parse_expr(ExampleExpressionString2)
print '(ExampleExpressionSympy1 == ExampleExpressionSympy2):'
print ' ', (ExampleExpressionSympy1 == ExampleExpressionSympy2)
print '(ExampleExpressionSympy1.simplify() == ExampleExpressionSympy2.simplify()):'
print ' ', (ExampleExpressionSympy1.simplify() == ExampleExpressionSympy2.simplify())
print '(ExampleExpressionSympy1.expand() == ExampleExpressionSympy2.expand()):'
print ' ', (ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp())
print '(ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp()):'
print ' ', (ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp())
print '(ExampleExpressionSympy1.simplify().expand().trigsimp() == ExampleExpressionSympy2.simplify().expand().trigsimp()):'
print ' ', (ExampleExpressionSympy1.simplify().expand().trigsimp() == ExampleExpressionSympy2.simplify().expand().trigsimp())
MORE NOTES:
I suspect this is a difficult problem to solve generically, and robustly. To properly check mathematical equivalence, you not only have to try order permutations, but you also have to have a library of mathematical equivalent transformations and try all those permutations as well.
I do however believe this might be a solvable problem, because Wolfram Alpha seems to have 'alternate expression' section, which seems to do the trick of providing all permutations most of the time on arbitrary expressions using these kinds of equivalences.
IN SUMMATION:
I suggest the following with the expectation that it will break:
import sympy
import sympy.parsing.sympy_parser
Expression.simplify().expand().trigsimp()

Categories