Sage can (awkwardly) do some simplifications of symbolic sums. For example
sage: var("j,p", domain="integer")
(j, p)
sage: X,Y=function("X,Y")
sage: (sum(X(j),j,1,p)+sum(Y(j),j,1,p)).maxima_methods().sumcontract()
sum(X(j) + Y(j), j, 1, p)but, to the best of my (limited) knowledge, the reverse operation, useful in sime situations (trivial example : derive maximum likelihood estimators of the parameters of some distributions) is not possible (in other words,
sum does not distribute over
+).
The needed function can be written in Sage :
def expand_sum(ex):
## Only way I found to denote the needed operator constants
def init_consts():
a=function("a")
b,c,d=SR.var("b,c,d")
op_sum=sum(a(b),b,c,d).operator()
op_add=(c-b).operator()
return(op_sum,op_add)
## Build a term of the result
def treat_term(term,loopargs):
L=copy(loopargs) ## Copy is needed, under penalty of side effects !!
L.insert(0,term)
return(apply(sum,L))
op_sum,op_add=init_consts()
if ex.parent() is not SR:return(ex)
op=ex.operator()
largs=ex.operands()
if op is None:return(ex)
if op is op_sum:
fa=largs[0]
op1=fa.operator()
if op1 is op_add:
ra=largs[1:] # index variable and bounds
return(sum(map(lambda t:treat_term(expand_sum(t),ra),
fa.operands())))
## Default case : recurse to ex arguments
return(apply(op, map(expand_sum, largs)))It can also be written in Maxima (or in lisp) and used via one of the Maxima interfaces :
expand_sum(ex):=block([sum_op,add_op,a,b,c,d],
sum_op:op(sum(a(b),b,c,d)),
add_op:op(c-b),
if atom(ex)
then ex
else block([op1:op(ex), largs:args(ex)],
if equal(op1,sum_op)
and not(atom(largs[1]))
and equal(op(args(ex)[1]), add_op)
then block([fa:first(largs), ra:rest(largs), lres,z],
lres:map(lambda([t],apply(sum,append([expand_sum(t)],ra))), args(fa)),
lsum(z,z,lres))
else apply(op1, map(expand_sum, largs))));Both versions allow the needed expansion. In Sage :
sage: load("/home/charpent/Feuilles Sage brutes/expand_sum.sage")
sage: expand_sum(sum(X(j)+Y(j),j,1,p))
sum(X(j), j, 1, p) + sum(Y(j), j, 1, p)(the Maxima version also works (not shown)). Hence a few questions :
- Did I oversee an existing way to do this ?
- Is that a worthwile addition to Sage ?
- Should it be implemented in Sage (probably as a method for SR), or via Maxima (like other sum functions) ?
- Should this be a special case of the expand() method ?
- Are there possible improvements (I think so : for example, I have been unable to find the "right" designation of the operators : op_sum might be sage.functions.other.symbolic_sum, but I found nothing usable for op_add, hence the ridiculous re-computation of these constants at each call...).
Sincerely,
--
Emmanuel Charpentier