Reputation: 4327
I have a rational (here: bilinear) expression and want I sympy to collect the coefficients. But how?
from sympy import symbols, Wild, pretty_print
a, b, c, d, x, s = symbols("a b c d x s")
def coeffs(expr):
n0 = Wild("n0", exclude=[x])
n1 = Wild("n1", exclude=[x])
d0 = Wild("d0", exclude=[x])
d1 = Wild("d1", exclude=[x])
match = expr.match((n0 + n1*x) / (d0 + d1*x))
n0 = n0.xreplace(match)
n1 = n1.xreplace(match)
d0 = d0.xreplace(match)
d1 = d1.xreplace(match)
return [n0, n1, d0, d1]
if __name__ == '__main__':
pretty_print(coeffs((a + b*x) / (c + d*x)))
pretty_print(coeffs(2 * (a + b*x) / (c + d*x)))
pretty_print(coeffs(s * (a + b*x) / (c + d*x)))
I tried this using match
, but it fails almost always, for example in the last line (the one with a symbolic prefactor of "s") I get
Traceback (most recent call last):
File "...", line 20, in <module>
pretty_print(coeffs(s * (a + b*x) / (c + d*x)))
File "...", line 11, in coeffs
n0 = n0.xreplace(match)
File "/usr/lib/python3/dist-packages/sympy/core/basic.py", line 1626, in xreplace
return rule.get(self, self)
AttributeError: 'NoneType' object has no attribute 'get'
so the match did not work.
Upvotes: 3
Views: 1773
Reputation: 5521
If you know that the expressions you will consider are rational, you could extract their numerator and denominator and find their coefficients independently.
Here's one approach to do so:
import sympy as sp
def get_rational_coeffs(expr):
num, denom = expr.as_numer_denom()
return [sp.Poly(num, x).all_coeffs(), sp.Poly(denom, x).all_coeffs()]
a, b, c, d, x, s = sp.symbols("a b c d x s")
expr = (a + b*x) / (c + d*x)
# note the order of returned coefficients
((n1, n0), (d1, d0)) = get_rational_coeffs(s*expr)
print(((n0, n1), (d0, d1)))
((a*s, b*s), (c, d))
The above approach is also faster than coeffs
. I get the following timings (based on Jupyter's %timeit
magic) for the case where the coefficients of expr
are required (case where coeffs
succeeds):
%timeit get_rational_coeffs(expr)
%timeit coeffs(expr)
1000 loops, best of 3: 1.33 ms per loop
1000 loops, best of 3: 1.99 ms per loop
Upvotes: 4