Description
Motivation : some "obvious" transformations, sometimes helpful in routine calculations, cannot be obtained via the current methods. Some (elementary,
i. e. high-school- or undergrad-level) exemples : given the declarations :
var("a,b")
var("j,p", domain="integer")
f,g,X=function("f,g,X")
the following equalities, true under no or mild conditions, cannot be deduced currently :
sum(X(j)+Y(j),j,1,p)==sum(X(j),j,1,p)+sum(Y(j),j,1,p) ## (1)
prod(X(j)*Y(j),j,1,p)==prod(X(j),j,1,p)*prod(Y(j),j,1,p) ## (2)
integrate(f(x)+g(x),x,a,b)==integrate(f(x),x,a,b)+integrate(g(x),x,a,b) ## (3)
Similarly, if A, B and C are matrices over a suitable ring and of
suitable dimensions, the following equalities cannot be
straightforwardly obtained.
(A+B).trace()==A.trace()+B.trace() ## (4)
(A*B).det()==A.det()*B.det() ## (5)
(Curiously, (f(x)+g(x)).diff(x)
does return
diff(f(x),x)+diff(g(x),x)
(and a way to return to the original
expression does not seem to exist currently)).
The ability to generate the right-hand form from the left-hand form of
these various examples is sometimes useful in (low-level)
examples. The examples (1) and/or (2) arise naturally when deriving the
maximum-likelihood estimators of the mean and variance of a given
distribution. The third one is often encountered in elementary calculus
exercises.
In all cases, an operator is "distributed" over another one :
(1) : symbolic_sum is distributed over addition.
(2) : symbolic product is distributed over multiplication.
(3) : integration is ditributed over addition.
(4) : trace is distributed over (matrix) addition.
(5) : determinant is distributed over (matrix) multiplication.
Implementing (1) as an extension of the expand()
method of
Expression is tempting (see #22915). However, there are situations
where this expansion is not useful. So, creating a method for such
situations seems useful.
One should note that such "distributions" are not systematically
valid : we have a collection of special cases rather than a general
mechanism. So this method shoud either limit itself to a few
recognized cases or take keyword argument(s) specifying what should be
distributed over what.
Another design choice is to know if these distributions should be
recursive or run only on the top level of a given expression
(possibly controlled by another keyword argument).
The present ticket aims at implementing this method for sage.symbolic.expression.Expression
, at least in cases (1) to (3) (case (2) needs an implementation of the symbolic products, see #17505). Further suggestions for other classes are welcome...
Depends on #17505
Upstream: None of the above - read trac for reasoning.
Component: symbolics
Author: Emmanuel Charpentier, Ralf Stephan
Branch: 7aee739
Reviewer: Travis Scrimshaw
Issue created by migration from https://trac.sagemath.org/ticket/22937