RootSum – sums over the roots of a polynomial.

A RootSumFunction represents a symbolic expression of the form

\[F(x) = \sum_{r : P(r) = 0} f(r, x)\]

where \(P\) is a univariate polynomial, the sum runs over all roots \(r\) of \(P\) (counted with multiplicity), and \(f\) is a symbolic expression that may involve \(r\) and any number of free variables.

Such expressions arise, for example, as antiderivatives of rational functions whose denominator does not factor over the coefficient field. They are produced by Maxima, FriCAS, Wolfram and SymPy. The classical example (see also R. Fateman, “Simplifying RootSum Expressions”) is

\[\int \frac{dx}{x^3 + a x + 1} = \sum_{r : r^3 + a r + 1 = 0} \frac{\log(x - r)}{a + 3 r^2}.\]

The root variable is bound. Substitution acts on free occurrences only, and alpha-renames the root variable when needed to avoid capture. Bound names are normalized at construction, so alpha-equivalent root sums have identical symbolic representations. As with other symbolic expressions, variables() lists all occurring symbols; use free_variables() to obtain the unbound ones.

INPUT:

  • poly – a univariate polynomial, given as a symbolic expression, for example r^3 + a*r + 1

  • root_var – the symbolic variable that is summed over; it must occur in poly

  • summand – a symbolic expression in root_var (and possibly other free variables) giving the term to sum

OUTPUT:

A symbolic expression representing \(\sum_{r:P(r)=0} f(r)\).

EXAMPLES:

sage: from sage.symbolic.rootsum import root_sum
sage: var('x a r')
(x, a, r)
sage: P = r^3 + a*r + 1
sage: rs = root_sum(P, r, log(x - r)/(a + 3*r^2))
sage: rs
root_sum(r^3 + a*r + 1, r, log(-r + x)/(3*r^2 + a))
>>> from sage.all import *
>>> from sage.symbolic.rootsum import root_sum
>>> var('x a r')
(x, a, r)
>>> P = r**Integer(3) + a*r + Integer(1)
>>> rs = root_sum(P, r, log(x - r)/(a + Integer(3)*r**Integer(2)))
>>> rs
root_sum(r^3 + a*r + 1, r, log(-r + x)/(3*r^2 + a))
from sage.symbolic.rootsum import root_sum
var('x a r')
P = r^3 + a*r + 1
rs = root_sum(P, r, log(x - r)/(a + 3*r^2))
rs

The three operands are accessible directly:

sage: rs.operands()[0]
r^3 + a*r + 1
sage: rs.operands()[1]
r
sage: rs.operands()[2]
log(-r + x)/(3*r^2 + a)
>>> from sage.all import *
>>> rs.operands()[Integer(0)]
r^3 + a*r + 1
>>> rs.operands()[Integer(1)]
r
>>> rs.operands()[Integer(2)]
log(-r + x)/(3*r^2 + a)
rs.operands()[0]
rs.operands()[1]
rs.operands()[2]

Substituting a free variable preserves the expression:

sage: rs.subs(a == 0)
root_sum(r^3 + 1, r, 1/3*log(-r + x)/r^2)
>>> from sage.all import *
>>> rs.subs(a == Integer(0))
root_sum(r^3 + 1, r, 1/3*log(-r + x)/r^2)
rs.subs(a == 0)

A low-degree polynomial evaluates explicitly when its roots are available:

sage: root_sum(r^2 - 1, r, r^2)
2
>>> from sage.all import *
>>> root_sum(r**Integer(2) - Integer(1), r, r**Integer(2))
2
root_sum(r^2 - 1, r, r^2)

A quintic stays unevaluated:

sage: root_sum(r^5 - r + 1, r, sin(r))
root_sum(r^5 - r + 1, r, sin(r))
>>> from sage.all import *
>>> root_sum(r**Integer(5) - r + Integer(1), r, sin(r))
root_sum(r^5 - r + 1, r, sin(r))
root_sum(r^5 - r + 1, r, sin(r))

The derivative of a root sum is again a root sum, taken under the sum:

sage: rs.diff(x)
1/(x^3 + a*x + 1)
>>> from sage.all import *
>>> rs.diff(x)
1/(x^3 + a*x + 1)
rs.diff(x)

The motivating application is antidifferentiation of rational functions. The derivative of the returned root sum equals the integrand:

sage: # needs sympy
sage: F = integrate(1/(x^3 + a*x + 1), x, algorithm='sympy')
sage: D = F.diff(x)
sage: val = root_sum.evaluate(D.subs(a == 1, x == 1), prec=100)
sage: abs(val - 1/3) < 1e-25
True
>>> from sage.all import *
>>> # needs sympy
>>> F = integrate(Integer(1)/(x**Integer(3) + a*x + Integer(1)), x, algorithm='sympy')
>>> D = F.diff(x)
>>> val = root_sum.evaluate(D.subs(a == Integer(1), x == Integer(1)), prec=Integer(100))
>>> abs(val - Integer(1)/Integer(3)) < RealNumber('1e-25')
True
# needs sympy
F = integrate(1/(x^3 + a*x + 1), x, algorithm='sympy')
D = F.diff(x)
val = root_sum.evaluate(D.subs(a == 1, x == 1), prec=100)
abs(val - 1/3) < 1e-25
class sage.symbolic.rootsum.RootSumFunction[source]

Bases: BuiltinFunction

The symbolic function root_sum.

See the module docstring for details.

evaluate(expr, prec=53)[source]

Numerically evaluate an expression containing root sums.

Exact squarefree decomposition preserves multiplicities before numerical root finding. prec is working bit precision; it does not certify the relative error of a nearly cancelling sum.

EXAMPLES:

sage: r = var('r')
sage: rs = root_sum(r^5-r+1, r, sin(r))
sage: root_sum.evaluate(rs, prec=100)
-0.041691470337868009879662475806
sage: root_sum.evaluate(root_sum((r-1)^5, r, r))
5.00000000000000
sage: root_sum.evaluate(1 + rs, prec=100)
0.95830852966213199012033752419
>>> from sage.all import *
>>> r = var('r')
>>> rs = root_sum(r**Integer(5)-r+Integer(1), r, sin(r))
>>> root_sum.evaluate(rs, prec=Integer(100))
-0.041691470337868009879662475806
>>> root_sum.evaluate(root_sum((r-Integer(1))**Integer(5), r, r))
5.00000000000000
>>> root_sum.evaluate(Integer(1) + rs, prec=Integer(100))
0.95830852966213199012033752419
r = var('r')
rs = root_sum(r^5-r+1, r, sin(r))
root_sum.evaluate(rs, prec=100)
root_sum.evaluate(root_sum((r-1)^5, r, r))
root_sum.evaluate(1 + rs, prec=100)