Skip to content

Commit

Permalink
Trac #17659: make symbolic series subclass of Expression
Browse files Browse the repository at this point in the history
Making `Expression.series` create `SymbolicSeries` (a subclass of
`Expression`) and moving the series code into a separate file
`series.pyx`
* reflects the fact that expressions and series don't commute
* allows upcoming fixes that don't clutter `Expression` methods with `if
ex.is_a_series():`
* makes for better documentation via having a `Symbolic Series` ref man
page

In refactoring language this is "replace conditional with polymorphism".

#16203, #17400, and #17402 depend on this.

URL: http://trac.sagemath.org/17659
Reported by: rws
Ticket author(s): Ralf Stephan
Reviewer(s): Vincent Delecroix
  • Loading branch information
Release Manager authored and vbraun committed Jan 29, 2016
2 parents ce8543a + 1832f4a commit b5d4ef1
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 62 deletions.
1 change: 1 addition & 0 deletions src/doc/en/reference/calculus/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Symbolic Calculus
sage/symbolic/function
sage/symbolic/function_factory
sage/calculus/functional
sage/symbolic/series
sage/symbolic/integration/integral
sage/symbolic/integration/external
sage/calculus/test_sympy
Expand Down
86 changes: 24 additions & 62 deletions src/sage/symbolic/expression.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import sage.rings.integer
import sage.rings.rational
from sage.structure.element cimport ModuleElement, RingElement, Element
from sage.symbolic.getitem cimport OperandsWrapper
from sage.symbolic.series cimport SymbolicSeries
from sage.symbolic.complexity_measures import string_length
from sage.symbolic.function import get_sfunction_from_serial, SymbolicFunction
from sage.rings.rational import Rational # Used for sqrt.
Expand Down Expand Up @@ -2110,60 +2111,23 @@ cdef class Expression(CommutativeRingElement):

def is_series(self):
"""
Return True if ``self`` is a series.
Series are special kinds of symbolic expressions that are
constructed via the :meth:`series` method. They usually have
an ``Order()`` term unless the series representation is exact,
see :meth:`is_terminating_series`.
OUTPUT:
Boolean. Whether ``self`` is a series symbolic
expression. Usually, this means that it was constructed by the
:meth:`series` method.
Returns ``False`` if only a subexpression of the symbolic
expression is a series.
EXAMPLES::
TESTS::
sage: SR(5).is_series()
False
sage: var('x')
x
sage: x.is_series()
False
sage: exp(x).is_series()
False
sage: exp(x).series(x,10).is_series()
True
Laurent series are series, too::
sage: laurent_series = (cos(x)/x).series(x, 5)
sage: laurent_series
1*x^(-1) + (-1/2)*x + 1/24*x^3 + Order(x^5)
sage: laurent_series.is_series()
True
Something only containing a series as a subexpression is not a
series::
sage: sum_expr = 1 + exp(x).series(x,5); sum_expr
(1 + 1*x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + Order(x^5)) + 1
sage: sum_expr.is_series()
doctest:...: DeprecationWarning: ex.is_series() is deprecated. Use isinstance(ex, sage.symbolic.series.SymbolicSeries) instead
See http://trac.sagemath.org/17659 for details.
False
"""
return is_a_series(self._gobj)
from sage.misc.superseded import deprecation
deprecation(17659, "ex.is_series() is deprecated. Use isinstance(ex, sage.symbolic.series.SymbolicSeries) instead")
return False

def is_terminating_series(self):
"""
Return True if ``self`` is a series without order term.
A series is terminating if it can be represented exactly,
without requiring an order term. See also :meth:`is_series`
for general series.
without requiring an order term.
OUTPUT:
Expand All @@ -2174,8 +2138,6 @@ cdef class Expression(CommutativeRingElement):
sage: (x^5+x^2+1).series(x,10)
1 + 1*x^2 + 1*x^5
sage: (x^5+x^2+1).series(x,10).is_series()
True
sage: (x^5+x^2+1).series(x,10).is_terminating_series()
True
sage: SR(5).is_terminating_series()
Expand All @@ -2187,7 +2149,7 @@ cdef class Expression(CommutativeRingElement):
sage: exp(x).series(x,10).is_terminating_series()
False
"""
return g_is_a_terminating_series(self._gobj)
return False

cpdef bint is_polynomial(self, var):
"""
Expand Down Expand Up @@ -4030,6 +3992,7 @@ cdef class Expression(CommutativeRingElement):
"""
cdef Expression symbol0 = self.coerce_in(symbol)
cdef GEx x
cdef SymbolicSeries nex
cdef int prec
if order is None:
from sage.misc.defaults import series_precision
Expand All @@ -4039,9 +4002,12 @@ cdef class Expression(CommutativeRingElement):
sig_on()
try:
x = self._gobj.expand(0).series(symbol0._gobj, prec, 0)
nex = SymbolicSeries.__new__(SymbolicSeries)
nex._parent = self._parent
GEx_construct_ex(&nex._gobj, x)
finally:
sig_off()
return new_Expression_from_GEx(self._parent, x)
return nex

def residue(self, symbol):
"""
Expand Down Expand Up @@ -4206,9 +4172,7 @@ cdef class Expression(CommutativeRingElement):
sage: f.series(x==1,3).truncate().expand()
-2*x^2*cos(1) + 5/2*x^2*sin(1) + 5*x*cos(1) - 7*x*sin(1) - 3*cos(1) + 11/2*sin(1)
"""
if not is_a_series(self._gobj):
return self
return new_Expression_from_GEx(self._parent, series_to_poly(self._gobj))
return self

def expand(Expression self, side=None):
"""
Expand Down Expand Up @@ -5750,6 +5714,7 @@ cdef class Expression(CommutativeRingElement):
Series coefficients are now handled correctly (:trac:`17399`)::
sage: s=(1/(1-x)).series(x,6); s
1 + 1*x + 1*x^2 + 1*x^3 + 1*x^4 + 1*x^5 + Order(x^6)
sage: s.coefficients()
Expand All @@ -5770,19 +5735,15 @@ cdef class Expression(CommutativeRingElement):
[[t, 0], [3, 1], [1, 2]]
"""
f = self._maxima_()
maxima = f.parent()
maxima._eval_line('load(coeflist)')
if x is None:
x = self.default_variable()
if is_a_series(self._gobj):
l = [[self.coefficient(x, d), d] for d in xrange(self.degree(x))]
else:
f = self._maxima_()
maxima = f.parent()
maxima._eval_line('load(coeflist)')
G = f.coeffs(x)
from sage.calculus.calculus import symbolic_expression_from_maxima_string
S = symbolic_expression_from_maxima_string(repr(G))
l = S[1:]

G = f.coeffs(x)
from sage.calculus.calculus import symbolic_expression_from_maxima_string
S = symbolic_expression_from_maxima_string(repr(G))
l = S[1:]
if sparse is True:
return l
else:
Expand Down Expand Up @@ -11878,3 +11839,4 @@ cdef operators compatible_relation(operators lop, operators rop) except <operato
return greater
else:
raise TypeError("incompatible relations")

1 change: 1 addition & 0 deletions src/sage/symbolic/ginac.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ cdef extern from "sage/symbolic/ginac_wrap.h":
bint is_a_series "is_a<pseries>" (GEx e)
# you must ensure that is_a_series(e) is true before calling this:
bint g_is_a_terminating_series(GEx e) except +
GEx g_series_var(GEx e) except +

# Relations
ctypedef enum operators "relational::operators":
Expand Down
7 changes: 7 additions & 0 deletions src/sage/symbolic/ginac_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ bool g_is_a_terminating_series(const ex& e) {
return false;
}

ex g_series_var(const ex& e) {
if (is_a<pseries>(e)) {
return (ex_to<pseries>(e)).get_var();
}
return NULL;
}

relational::operators relational_operator(const ex& e) {
// unsafe cast -- be damn sure the input is a relational.
return (ex_to<relational>(e)).the_operator();
Expand Down
4 changes: 4 additions & 0 deletions src/sage/symbolic/series.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from sage.symbolic.expression cimport Expression

cdef class SymbolicSeries(Expression):
pass
Loading

0 comments on commit b5d4ef1

Please sign in to comment.