SymPy Expr.subs() method does not work within a Sum - sympy

I am trying to use sympy to start with a PDE, manipulate it symbolically to obtain a finite element formulation, and then apply code generation to obtain a code snippet for applying the results in an application.
As such, I want to start with Derivative objects, but at some point substitute a simple function in place of those derivatives, as the basis functions and derivatives of those basis functions will be stored by the code. In simple situations, this works:
>>> from sympy import *
>>> init_printing()
>>> i = Idx('i')
>>> x = Symbol('x')
>>> phi = Function('phi')(i,x)
>>> expr = Derivative(phi,x) + phi
>>> expr
d
φ(i, x) + ──(φ(i, x))
dx
>>> phi_x = Function('phi_x')(i,x)
>>> expr.subs(Derivative(phi,x), phi_x)
φ(i, x) + φₓ(i, x)
But if the derivatives appear within a summation, the substitution fails:
>>> N = Symbol('N', integer=True)
>>> expr = summation(Derivative(phi,x) + phi, (i,0,N-1))
>>> expr
N - 1
____
╲
╲ ⎛ d ⎞
╲ ⎜φ(i, x) + ──(φ(i, x))⎟
╱ ⎝ dx ⎠
╱
╱
‾‾‾‾
i = 0
>>> expr.subs(Derivative(phi,x), phi_x)
N - 1
____
╲
╲ ⎛ d ⎞
╲ ⎜φ(i, x) + ──(φ(i, x))⎟
╱ ⎝ dx ⎠
╱
╱
‾‾‾‾
i = 0
Does anyone have an idea why this might be, or what a workaround might be?
TIA!

I'm not sure why this doesn't work (as it should according to expression semantics), but here's a workaround:
from sympy import *
def substitution_in_sum(expr,old_sub_expr,new_sub_expr):
if expr == old_sub_expr:
return new_sub_expr
elif expr.args==():
return expr
else:
result_list = []
for arg in expr.args:
result_list.append(substitution_in_sum(arg,old_sub_expr,new_sub_expr))
return expr.func(*tuple(result_list))

Related

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

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)

SymPy cannot rearrange results while solving a system of equations about Stackelberg game

Function f (assume n=3 for simplicity):
There are 3 symbols related to entities, corresponding to x[j](j=1,2,3) respectively. R and c is other symbols, which can be treated like constant for now. I try to diff f w.r.t x[j], and solve the results equations together and get x[j]=g(R,c). However, sympy cannot rearrange or split x[j] from the equation.
Derivatives:
Expected Results:
from sympy import *
import sympy as sym
real_n = 3
x = IndexedBase('x')
j, k, n = symbols('j,k n', cls=Idx)
f = x[j]*Symbol("R")/Sum(x[k],(k,1,real_n))-Symbol("c")*x[j]
equ = diff(f,x[j])
ee = solve([equ.subs(j,1),equ.subs(j,2),equ.subs(j,3)], (x[1],x[2],x[3]))
simplify(ee)
Sympy's result:
{x[1]: (R*Sum(x[k], (k, 1, 3)) - c*Sum(x[k], (k, 1, 3))**2)/(R*Sum(KroneckerDelta(1, k), (k, 1, 3))),
x[2]: (R*Sum(x[k], (k, 1, 3)) - c*Sum(x[k], (k, 1, 3))**2)/(R*Sum(KroneckerDelta(2, k), (k, 1, 3))),
x[3]: (R*Sum(x[k], (k, 1, 3)) - c*Sum(x[k], (k, 1, 3))**2)/(R*Sum(KroneckerDelta(3, k), (k, 1, 3)))}
I tried to check if the indexed symbol caused the error, and wrote x[i] as 3 different symbols, but it still didn't work.
from sympy import *
a, b, c = symbols('a b c', cls=Idx)
R = symbols("R")
eq1 = diff(a/(a+b+c)-a*R,a)
eq2 = diff(b/(a+b+c)-b*R,b)
eq3 = diff(c/(a+b+c)-c*R,c)
print(eq1,"\n",eq2,"\n",eq3)
solve([eq1,eq2,eq3], [a,b,c])
Output:
-R + 1/(a + b + c) - a/(a + b + c)**2
-R + 1/(a + b + c) - b/(a + b + c)**2
-R + 1/(a + b + c) - c/(a + b + c)**2
[]
Is there something wrong with my approach? Is it possible to approach this problem in SymPy from another angle?
Any suggestions for the solution of equations are also most welcome.
You can use doit to expand the summation and then solve:
In [6]: solve([equ.subs(j,1).doit(),equ.subs(j,2).doit(),equ.subs(j,3).doit()], (x[1],x[2],x[3]))
Out[6]:
⎡⎛ ____ ⎞⎤
⎢⎜ ╱ 2 ⎟⎥
⎢⎜R + 3⋅╲╱ R 2⋅R 2⋅R⎟⎥
⎢⎜─────────────, ───, ───⎟⎥
⎣⎝ 18⋅c 9⋅c 9⋅c⎠⎦

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.

Getting used indices of indexed terms in a sympy sum

Say I have variables x and y which are indexed
from sympy.tensor import IndexedBase
x = IndexedBase('x')`
And I have an expression like e = x[1] y[2] + x[5] y[10]
. I want to find all indices used by each of x and y. I'm looking for a function which might work like this: e.indices(y) = [2, 10] and e.indicies(x) = [1, 5]
Is there a way I can iterate through the terms x[i] y[j]? And if so, is there a way to split a product into terms and for each of those pull out which letter is being used and which index appears?
The following should get you headed in the right direction:
>>> from sympy.tensor import IndexedBase, Indexed
>>> from sympy import sift
>>> x = IndexedBase('x')
>>> y = IndexedBase('y')
>>> e = x[1]* y[2] + x[5]* y[10]
>>> e.atoms(IndexedBase)
set([y, x])
>>> e.atoms(Indexed)
set([x[5], y[10], x[1], y[2]])
>>> sifted = sift(_,lambda i: i.base)
>>> sifted[x]
[x[5], x[1]]
>>> sifted[y]
[y[10], y[2]]
>>> [i.indices for i in _]
[(10,), (2,)]
>>> flatten(_)
[10, 2]

Sympy substitution of x[i]*x[j] with x[i,j]

I have an indexed symbol x in Sympy and an expression which is a sum of second degree monomials like x[1]*x[2] + x[3]**2 + x[4]*x[1]. I would like to turn such an expression into x[1,2] + x[3,3] + x[4,1], i.e. replacing x[i]*x[j] -> x[i,j]
There is an upper bound on the indices which may appear, so I could construct a large table hard coding each substitution. Is there a better way?
Responding to the comment - to create x I write
from sympy.tensor import IndexedBase
x = IndexedBase('x')
You can use ordered to put the indices in order:
>>> from sympy import *
>>> i, j = symbols('i j', cls=Wild)
>>> x = IndexedBase('x')
>>> e = x[1]*x[3] + x[2]*x[1] + x[3]**2
>>> def new(o, x):
... if o.is_Mul:
... i,j=list(ordered([i.args[1] for i in o.args]))
... elif o.is_Pow:
... i = j = o.base.args[1]
... else:
... raise NotImplementedError
... return x[i, j]
...
>>> e.xreplace(dict([(o, new(o, x)) for o in e.find(x[i]*x[j])]))
x[1, 2] + x[1, 3] + x[3, 3]
But a simpler way to do the same thing is to use a Piecewise result in the replace call:
>>> e.replace(x[i]*x[j], Piecewise((x[i,j],i<j),(x[j,i],True)))
x[1, 2] + x[1, 3] + x[3, 3]
You can use replace with a Wild.
In [1]: i, j = symbols('i j', cls=Wild)
In [2]: x = IndexedBase('x')
In [3]: e = x[1]*x[3] + x[2]*x[1]
In [4]: e.replace(x[i]*x[j], x[i, j])
Out[4]: x[1, 2] + x[1, 3]