Sympy: Is there a function that gives all the factors of an expression but does not work sums? - sympy

I have an expression which is composed only of factors (e.g. (x**2+1)*(x**2)*(x+4). I want to delete the factor x**2 from it using the function .args with an if condition. However, if I have the following equation x**2+1+x+4, the .args thinks I have x**2 in the expression which is not true (I only have one factor). I have the code below.:
if q**2 in expr.args:
expr = expr.func(*[term for term in expr.args if term != q**2])
else:
expr = expr*2

By using Mul.make_args(expr) you will get a singleton if the expression is not a product, otherwise a tuple of the factors:
>>> from sympy.abc import x, y
>>> from sympy import Mul
>>> Mul.make_args(x + y)
(x + y,)
>>> Mul.make_args(x*y)
(x, y)

Related

How to generate random math expression trees with sympy?

I am scouring the web but I cannot find how to generate random math expressions with sympy. Is it even possible?
I would like to build an expression tree by randomly selecting functions (product, sum, cosine...) and symbols from a set of predefined functions and symbols.
For instance, given the set [+,.] of sum and product and the symbols [x,y] I'd like to generate expressions such as x+y, (x+y).x, y+(x.x+y)+x etc, controlling parameters as the tree depth, width and the number of nodes.
Any hints?
Something like the following might help you get started:
from random import choice, randint
from sympy import FunctionClass, Add, Mul, cos, sin, binomial, arity, S
def args(n, atoms, funcs):
a = funcs+atoms
g = []
for _ in range(n):
ai = choice(a)
if isinstance(ai, FunctionClass):
g.append(ai(*args(arity(ai), atoms, funcs)))
else:
g.append(ai)
return g
def expr(ops, atoms, funcs=()):
types = [Add, Mul]
atoms = tuple(atoms)
while 1:
e = S.Zero
while e.count_ops() < ops:
_ = choice(types)(*args(randint(1,3), atoms, funcs))
e = choice(types)(e, _)
if e is S.NaN: break
else:
return e
>>> [expr(5, (-1,0,1,x,y)) for do in range(2)]
[(x - 1)*(2*x + y + 2), x + y*(x + 4*y - 2) + y]
>>> expr(5, (-1,0,1,x,y), (cos, binomial))
x*y**2 + x + cos(1)
>>> expr(5, (-1,0,1,x,y), (cos, binomial))
(y + zoo*binomial(y, x) - 2)*(y + cos(1) + 1)
To generate rational expressions you could change make the 2nd _ arg be _**choice((1,-1)).

Sympy Piecewise and refine

I try to simplify this Piecewise expression using refine without success. I use sympy version 1.8.
import sympy as sp
x,y = sp.symbols('x,y', real=True, positive=True)
expr = sp.Piecewise((1, x>=y),(0, True))
expr variable contain
⎧1 for x ≥ y
⎨
⎩0 otherwise
now I try to obtain 1 assuming that x>y
sp.refine(expr, sp.Q.gt(x,y))
but I obtain the same expression
⎧1 for x ≥ y
⎨
⎩0 otherwise
Any ideas to force this simplification ?
Thank you for your help
If you give expr a value for x that satisfies the requirement, it will evaluate:
>>> eps = Symbol('eps', positive=True)
>>> expr.subs(x, y + eps).simplify()
1

Sympy .replace() doesn't detect product

I'm trying to make some replacements, but .replace() is confusingly missing occurrences:
from sympy import *
x, y = symbols('x y')
f = Function('f')
expr = x*f(x)*f(y)
expr.replace(x*f(x), 1)
# Output: x*f(x)*f(y)
# Expected: f(y)
Is this a bug?
It does work when I use .subs() instead of .replace(), but I have no idea why this would be needed.
(also, I wanna use this in the context of a Sum expression where .subs() would not work).

Using `replace` to put terms under a common denominator with sympy

I'm trying to get a subexpression of a larger expression under a common denominator. However, when I use replace() for this, it applies to sums of functions, even though there's no ratio.
>>> x = Function('x')(t)
>>> f = Function('f')(t)
>>> g = Function('g')(t)
>>> a,b = Wild('a'), Wild('b')
>>> f + g
f(t) + g(t)
>>> (f + g).replace(a/x+b/x, (a+b)/x)
f(t)⋅x(t) + g(t)⋅x(t)
─────────────────────
x(t)
How do I get this to apply only where the original source expression has an explicit / x(t) in both terms?
Note: if either f & g, or x, are Symbols, rather than UndefinedFunctions, no replacement happens, which is what I want.

How to rewrite an abstract derivative of a sum as a sum of derivatives in sympy?

I want to convert (L + L')' into L' + L'' using sympy and some sort of expanding or simplifying function.
import sympy
sympy.init_printing() # math as latex
z, L = sympy.symbols('z,L')
expr = sympy.Derivative(L + sympy.Derivative(L,z), z)
expr
I tried standard functions like expand, which rewrites the expression (even with a flag force=True), or doit which returns zero.
Question. Is there a way to apply sp.Derivative to sum of two functions and expand it to sum of sp.Derivative's?
If we work with derivatives, it is better to use sympy.Function instead of sympy.Symbol. In order to expand the derivative, one can use .doit() method.
Example.
import sympy
sympy.init_printing() # math as latex
z = sympy.Symbol('z')
f = sympy.Function("f")(z)
expr = sympy.Derivative(sympy.Derivative(f) + f)
expr
expr.doit()