Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit a018030

Browse files
Merge branch 'u/rws/implement_symbolic_product' of trac.sagemath.org:sage into distribute
2 parents 7f9666a + 7a56004 commit a018030

File tree

4 files changed

+186
-4
lines changed

4 files changed

+186
-4
lines changed

src/sage/calculus/calculus.py

+101-1
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,103 @@ def nintegral(ex, x, a, b,
809809

810810
nintegrate = nintegral
811811

812+
def symbolic_product(expression, v, a, b, algorithm='maxima', hold=False):
813+
r"""
814+
Return the symbolic product `\prod_{v = a}^b expression` with respect
815+
to the variable `v` with endpoints `a` and `b`.
816+
817+
INPUT:
818+
819+
- ``expression`` - a symbolic expression
820+
821+
- ``v`` - a variable or variable name
822+
823+
- ``a`` - lower endpoint of the product
824+
825+
- ``b`` - upper endpoint of the prduct
826+
827+
- ``algorithm`` - (default: ``'maxima'``) one of
828+
829+
- ``'maxima'`` - use Maxima (the default)
830+
831+
- ``'giac'`` - (optional) use Giac
832+
833+
- ``'sympy'`` - use SymPy
834+
835+
- ``hold`` - (default: ``False``) if ``True`` don't evaluate
836+
837+
EXAMPLES::
838+
839+
sage: i, k, n = var('i,k,n')
840+
sage: from sage.calculus.calculus import symbolic_product
841+
sage: symbolic_product(k, k, 1, n)
842+
factorial(n)
843+
sage: symbolic_product(x + i*(i+1)/2, i, 1, 4)
844+
x^4 + 20*x^3 + 127*x^2 + 288*x + 180
845+
sage: symbolic_product(i^2, i, 1, 7)
846+
25401600
847+
sage: f = function('f')
848+
sage: symbolic_product(f(i), i, 1, 7)
849+
f(7)*f(6)*f(5)*f(4)*f(3)*f(2)*f(1)
850+
sage: symbolic_product(f(i), i, 1, n)
851+
product(f(i), i, 1, n)
852+
sage: assume(k>0)
853+
sage: symbolic_product(integrate (x^k, x, 0, 1), k, 1, n)
854+
1/factorial(n + 1)
855+
sage: symbolic_product(f(i), i, 1, n).log().log_expand()
856+
sum(log(f(i)), i, 1, n)
857+
"""
858+
if not is_SymbolicVariable(v):
859+
if isinstance(v, str):
860+
v = var(v)
861+
else:
862+
raise TypeError("need a multiplication variable")
863+
864+
if v in SR(a).variables() or v in SR(b).variables():
865+
raise ValueError("product limits must not depend on the multiplication variable")
866+
867+
if hold == True:
868+
from sage.functions.other import symbolic_prod as sprod
869+
return sprod(expression, v, a, b)
870+
871+
if algorithm == 'maxima':
872+
return maxima.sr_prod(expression,v,a,b)
873+
874+
elif algorithm == 'mathematica':
875+
try:
876+
prod = "Product[%s, {%s, %s, %s}]" % tuple([repr(expr._mathematica_()) for expr in (expression, v, a, b)])
877+
except TypeError:
878+
raise ValueError("Mathematica cannot make sense of input")
879+
from sage.interfaces.mathematica import mathematica
880+
try:
881+
result = mathematica(prod)
882+
except TypeError:
883+
raise ValueError("Mathematica cannot make sense of: %s" % sum)
884+
return result.sage()
885+
886+
elif algorithm == 'giac':
887+
prod = "product(%s, %s, %s, %s)" % tuple([repr(expr._giac_()) for expr in (expression, v, a, b)])
888+
from sage.interfaces.giac import giac
889+
try:
890+
result = giac(prod)
891+
except TypeError:
892+
raise ValueError("Giac cannot make sense of: %s" % sum)
893+
return result.sage()
894+
895+
elif algorithm == 'sympy':
896+
expression,v,a,b = [expr._sympy_() for expr in (expression, v, a, b)]
897+
from sympy import product as sproduct
898+
result = sproduct(expression, (v, a, b))
899+
try:
900+
return result._sage_()
901+
except AttributeError:
902+
raise AttributeError("Unable to convert SymPy result (={}) into"
903+
" Sage".format(result))
904+
905+
else:
906+
raise ValueError("unknown algorithm: %s" % algorithm)
907+
908+
812909
def minpoly(ex, var='x', algorithm=None, bits=None, degree=None, epsilon=0):
813910
r"""
814911
Return the minimal polynomial of self, if possible.
@@ -2024,7 +2121,10 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima):
20242121
formal_functions = maxima_tick.findall(s)
20252122
if len(formal_functions) > 0:
20262123
for X in formal_functions:
2027-
syms[X[1:]] = function_factory(X[1:])
2124+
try:
2125+
syms[X[1:]] = _syms[X[1:]]
2126+
except KeyError:
2127+
syms[X[1:]] = function_factory(X[1:])
20282128
# You might think there is a potential very subtle bug if 'foo
20292129
# is in a string literal -- but string literals should *never*
20302130
# ever be part of a symbolic expression.

src/sage/functions/other.py

+60-1
Original file line numberDiff line numberDiff line change
@@ -2593,8 +2593,10 @@ class Function_sum(BuiltinFunction):
25932593
EXAMPLES::
25942594
25952595
sage: from sage.functions.other import symbolic_sum as ssum
2596-
sage: ssum(x, x, 1, 10)
2596+
sage: r = ssum(x, x, 1, 10); r
25972597
sum(x, x, 1, 10)
2598+
sage: r.unhold()
2599+
55
25982600
"""
25992601
def __init__(self):
26002602
"""
@@ -2607,4 +2609,61 @@ def __init__(self):
26072609
BuiltinFunction.__init__(self, "sum", nargs=4,
26082610
conversions=dict(maxima='sum'))
26092611

2612+
def _print_latex_(self, x, var, a, b):
2613+
r"""
2614+
EXAMPLES::
2615+
2616+
sage: from sage.functions.other import symbolic_sum as ssum
2617+
sage: latex(ssum(x^2, x, 1, 10))
2618+
\sum_{x=1}^{10} x^2
2619+
"""
2620+
return r"\sum_{{{}={}}}^{{{}}} {}".format(var, a, b, x)
2621+
26102622
symbolic_sum = Function_sum()
2623+
2624+
2625+
class Function_prod(BuiltinFunction):
2626+
"""
2627+
Placeholder symbolic product function that is only accessible internally.
2628+
2629+
EXAMPLES::
2630+
2631+
sage: from sage.functions.other import symbolic_product as sprod
2632+
sage: r = sprod(x, x, 1, 10); r
2633+
product(x, x, 1, 10)
2634+
sage: r.unhold()
2635+
3628800
2636+
"""
2637+
def __init__(self):
2638+
"""
2639+
EXAMPLES::
2640+
2641+
sage: from sage.functions.other import symbolic_product as sprod
2642+
sage: _ = var('m n', domain='integer')
2643+
sage: r = maxima(sprod(sin(m), m, 1, n)).sage(); r
2644+
product(sin(m), m, 1, n)
2645+
sage: isinstance(r.operator(), sage.functions.other.Function_prod)
2646+
True
2647+
sage: r = sympy(sprod(sin(m), m, 1, n)).sage(); r # known bug
2648+
product(sin(m), m, 1, n)
2649+
sage: isinstance(r.operator(),
2650+
....: sage.functions.other.Function_prod) # known bug
2651+
True
2652+
sage: giac(sprod(m, m, 1, n))
2653+
n!
2654+
"""
2655+
BuiltinFunction.__init__(self, "product", nargs=4,
2656+
conversions=dict(maxima='product',
2657+
sympy='Product', giac='product'))
2658+
2659+
def _print_latex_(self, x, var, a, b):
2660+
r"""
2661+
EXAMPLES::
2662+
2663+
sage: from sage.functions.other import symbolic_product as sprod
2664+
sage: latex(sprod(x^2, x, 1, 10))
2665+
\prod_{x=1}^{10} x^2
2666+
"""
2667+
return r"\prod_{{{}={}}}^{{{}}} {}".format(var, a, b, x)
2668+
2669+
symbolic_product = Function_prod()

src/sage/interfaces/maxima_lib.py

+21
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@
232232
max_integrate=EclObject("$INTEGRATE")
233233
max_sum=EclObject("$SUM")
234234
max_simplify_sum=EclObject("$SIMPLIFY_SUM")
235+
max_prod=EclObject("$PRODUCT")
236+
max_simplify_prod=EclObject("$SIMPLIFY_PRODUCT")
235237
max_ratsimp=EclObject("$RATSIMP")
236238
max_limit=EclObject("$LIMIT")
237239
max_tlimit=EclObject("$TLIMIT")
@@ -898,6 +900,25 @@ def sr_sum(self,*args):
898900
else:
899901
raise
900902

903+
def sr_prod(self,*args):
904+
"""
905+
Helper function to wrap calculus use of Maxima's summation.
906+
"""
907+
try:
908+
return max_to_sr(maxima_eval([[max_ratsimp],[[max_simplify_prod],([max_prod],[sr_to_max(SR(a)) for a in args])]]));
909+
except RuntimeError as error:
910+
s = str(error)
911+
if "divergent" in s:
912+
# in pexpect interface, one looks for this;
913+
# could not find an example where 'Pole encountered' occurred, though
914+
# if "divergent" in s or 'Pole encountered' in s:
915+
raise ValueError("Sum is divergent.")
916+
elif "Is" in s: # Maxima asked for a condition
917+
self._missing_assumption(s)
918+
else:
919+
raise
920+
921+
901922
def sr_limit(self, expr, v, a, dir=None):
902923
"""
903924
Helper function to wrap calculus use of Maxima's limits.

src/sage/symbolic/expression_conversions.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -2008,12 +2008,14 @@ def composition(self, ex, operator):
20082008
sage: h()
20092009
0
20102010
"""
2011-
from sage.functions.other import Function_sum
2012-
from sage.calculus.calculus import symbolic_sum
2011+
from sage.functions.other import Function_sum, Function_prod
2012+
from sage.calculus.calculus import symbolic_sum, symbolic_product
20132013
if not operator:
20142014
return self
20152015
if isinstance(operator, Function_sum):
20162016
return symbolic_sum(*map(self, ex.operands()))
2017+
if isinstance(operator, Function_prod):
2018+
return symbolic_product(*map(self, ex.operands()))
20172019
if operator in self._exclude:
20182020
return operator(*map(self, ex.operands()), hold=True)
20192021
else:

0 commit comments

Comments
 (0)