'How to recognize exp or trig polynomials/fractions in SymPy
Let me define an exponential polynomial as a linear combination of terms exp(a*X)
where the a
s are distinct complex numbers. By taking only imaginary a
s we obtain a trig polynomial. Beware, though, that a term of the form exp(X*X)
or cos(X*X)
is not an exp/trig polynomial.
We define in the same way an exp/trig rational fraction as the quotient of two "polynomials" of the respective type described previously.
My question: given a sympy expression, how to recognize it is an exp/trig poly/frac?
My aim is to write a function is_exp_poly(expr)
returning a Boolean.
So far I've tried the following code, which rewrites my starting expression in a promising way:
X= Symbol('X')
expr= cos(2*X) * sin(pi*X)
trans= powsimp(expand(expr.rewrite(exp).subs(X : log(X)).rewrite(sympy.Pow)))
# results in: -I*X**(-2*I + I*pi)/4 - I*X**(2*I + I*pi)/4 + I*X**(-I*pi - 2*I)/4 + I*X**(-I*pi + 2*I)/4
From here I feel I should be able to answer my question. But I don't quite know how to identify an expression which is a linear combination of (non-int) powers (or a fraction thereof). By that, I mean using high-level sympy functions as opposed to analyzing directly the formula structure.
Would anyone be so kind as to help me solving my problem? Somehow I stumbled on this question which might be related, although the feature of Laurent Polynomials is still not implemented (as far as I understood the git issue's thread). It seems that I'm dealing with more complex expressions (although I don't plan to do anything as fancyful as factoring them).
Solution 1:[1]
Based on @smichr answer, this is how I solved the problem of recognizing an exp poly. Further obvious modifications completely answer my question.
x = numbered_symbols('x')
reps={}
trans=cancel(expr.rewrite(exp).expand().replace(lambda e: e.func is exp, lambda e: reps.setdefault(e, next(x))))
if trans.is_polynomial():
result=all([diff(e.args[0],X,2).is_zero and not "_rec_replace" in str(e) for e in reps.keys()])
else:
result=False
Solution 2:[2]
You can do something like this:
In [9]: X= Symbol('X')
...: expr= cos(2*X) * sin(pi*X)
In [10]: expr.atoms(sin, cos, exp)
Out[10]: {sin(??X), cos(2?X)}
In [11]: expr.as_poly(*expr.atoms(sin, cos, exp))
Out[11]: Poly((cos(2*X))*(sin(pi*X)), cos(2*X), sin(pi*X), domain='ZZ')
For rational functions you should be able to just use ratsimp
, together
, as_numer_denom
etc to get the numerator and denominator separately.
Solution 3:[3]
The following collects distinct exponentials and assigns a variable to them, replacing them in the expression which can then be tested to see if it meets your requirements:
>>> x = numbered_symbols('x')
>>> reps={}
>>> powsimp(expr.rewrite(exp).expand()).replace(lambda x: x.func is exp,
... lambda e: reps.setdefault(e, next(x)))
-I*x0/4 - I*x1/4 + I*x2/4 + I*x3/4
So the expression you gave is a linear combination of exponentials. The mapping between symbols and exponentials in in the reps
.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Oscar Benjamin |
Solution 3 | smichr |