## Separable next

So the next thing on my list is seperable differential equations. As I predicted in my proposal, I am going to have to do some work to get SymPy to recognize all equations that are separable. Currently, it can match expressions that are exactly written as $a(x)b(y)\frac{dy}{dx}+c(x)d(y)=0$, such as $x^2(y+2)\frac{dy}{dx}-y^3=0$ but the matching engine cannot get things like $(x^2y+2x^2)\frac{dy}{dx}+-y^3=0$, because it doesn’t know how to factor out the $x^2$. There is a function, collect, that can factor out expressions if you give them to it explicily with

collect(x**2*y+x**2,x**2)

but it doesn’t know yet how to separate variables in general. So I will be working on it this week. Once it can properly separate separable expressions, implementing it in dsolve will be cake.

Also, it needs to learn how to do $e^{x+y}\rightarrow e^{x}e^{y}$ and $1+x+y+xy \rightarrow (1+x)(1+y)$.

### 4 Responses to Separable next

1. vks says:

Did you try cse() + factor()?

• asmeurer says:

I know that factor can reduce the polynomial. I was just saying that I need to use it.

cse() doesn’t seem to do anything. Any expression I put in cse(expr) just returns [[],[expr,]].

I figured out what cse does from the examples, but I don’t see how that will help me separate expressions. It looks like it turns things like (x+y)**2+sqrt(x+y) into ([(x0, x + y)], [x0**(1/2) + x0**2]). It doesn’t even seem to work for exp(x+y), although ([(x0, x + y)], [exp(x0)]) is not what I want.

• vks says:

>>> e = sin(x)
>>> factor(e**2 + e)
Traceback (most recent call last):
File “”, line 1, in
File “sympy/polys/factortools.py”, line 80, in factor
coeff, factors = poly_factors(f, *symbols, **flags)
File “sympy/polys/factortools.py”, line 20, in poly_factors
f = Poly(f, *symbols)
File “sympy/polys/polynomial.py”, line 402, in __new__
terms = Poly._decompose(poly, *symbols)
File “sympy/polys/polynomial.py”, line 545, in _decompose
raise PolynomialError(“Can’t decompose %s” % factor)
sympy.polys.polynomial.PolynomialError: Can’t decompose sin(x)**2
>>> cse(e**2 + e)
([(x0, sin(x))], [x0 + x0**2])

Then you can substitute back:

>>> w, g = cse(e**2 + e)
>>> g = factor(g[0])
>>> g
x0*(1 + x0)
>>> g.subs(w[0][0], w[0][1]) # you’d have to iterate
(1 + sin(x))*sin(x)

> It doesn’t even seem to work for exp(x+y)

It should only replace x+y if it occurs multiple times:

>>> cse(exp(x+y))
([], [exp(x + y)]) # correct
>>> cse(exp(x+y)+x+y)
([], [x + y + exp(x + y)]) # wrong
>>> cse(exp(x+y)+x+y+sin(x+y))
([(x0, x + y)], [x0 + sin(x0) + exp(x0)]) # correct

I filed a bug report for the second case.

2. asmeurer says:

OK. I see what you mean now. cse() turns it into a polynomial which can then be handled by factor(). It seems to choke if it has too many transcendentals:
>>> e = expand(x*sin(x)*(y**2+sin(y)))
>>> e
x*y**2*sin(x) + x*sin(x)*sin(y)
>>> cse(e)
([(x0, sin(x))], [x*x0*sin(y) + x*x0*y**2])
>>> factor(cse(e)[1][0])
Traceback (most recent call last):
File “”, line 1, in
File “./sympy/polys/factortools.py”, line 80, in factor
coeff, factors = poly_factors(f, *symbols, **flags)
File “./sympy/polys/factortools.py”, line 20, in poly_factors
f = Poly(f, *symbols)
File “./sympy/polys/polynomial.py”, line 402, in __new__
terms = Poly._decompose(poly, *symbols)
File “./sympy/polys/polynomial.py”, line 545, in _decompose
raise PolynomialError(“Can’t decompose %s” % factor)
PolynomialError: Can’t decompose sin(y)

Compared to the simple separatevars function I wrote up:
>>> separatevars(e)
x*(sin(y) + y**2)*sin(x)

As for expanding exponentials, I will write a function that does that (it should be simple). Right now, I am working on fixing issue 252 so that they aren’t put right back together after I take them apart.