Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" The symbolic ring """
#***************************************************************************** # Copyright (C) 2008 William Stein <wstein@gmail.com> # Copyright (C) 2008 Burcin Erocal <burcin@erocal.org> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
from sage.ext.cplusplus cimport ccrepr
from sage.libs.pynac.pynac cimport *
from sage.rings.integer cimport Integer from sage.rings.real_mpfr cimport RealNumber
from sage.symbolic.expression cimport Expression, new_Expression_from_GEx, new_Expression_from_pyobject, is_Expression
from sage.misc.latex import latex_variable_name from sage.cpython.string cimport str_to_bytes, char_to_str from sage.structure.element cimport RingElement, Element, Matrix from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type
from sage.rings.all import RR, CC, ZZ
import operator
cdef class SymbolicRing(CommutativeRing): """ Symbolic Ring, parent object for all symbolic expressions. """ def __init__(self, base_ring = None): """ Initialize the Symbolic Ring.
EXAMPLES::
sage: SR Symbolic Ring
TESTS::
sage: isinstance(SR, sage.symbolic.ring.SymbolicRing) True sage: TestSuite(SR).run()
"""
def __reduce__(self): """ EXAMPLES::
sage: loads(dumps(SR)) == SR # indirect doctest True """
def _repr_(self): """ Return a string representation of self.
EXAMPLES::
sage: repr(SR) 'Symbolic Ring' """
def _latex_(self): """ Return latex representation of the symbolic ring.
EXAMPLES::
sage: latex(SR) \text{SR} sage: M = MatrixSpace(SR, 2); latex(M) \mathrm{Mat}_{2\times 2}(\text{SR}) """
cpdef _coerce_map_from_(self, R): """ EXAMPLES::
sage: SR.coerce(int(2)) 2 sage: SR.coerce(-infinity) -Infinity sage: SR.coerce(unsigned_infinity) Infinity sage: SR.has_coerce_map_from(ZZ['t']) True sage: SR.has_coerce_map_from(ZZ['t,u,v']) True sage: SR.has_coerce_map_from(Frac(ZZ['t,u,v'])) True sage: SR.has_coerce_map_from(GF(5)['t']) True sage: SR.has_coerce_map_from(SR['t']) False sage: SR.has_coerce_map_from(Integers(8)) True sage: SR.has_coerce_map_from(GF(9, 'a')) True sage: SR.has_coerce_map_from(RealBallField()) True sage: SR.has_coerce_map_from(ComplexBallField()) True sage: SR.has_coerce_map_from(UnsignedInfinityRing) True
TESTS::
sage: SR.has_coerce_map_from(pari) False
Check if arithmetic with bools works (see :trac:`9560`)::
sage: SR.has_coerce_map_from(bool) True sage: SR(5)*True; True*SR(5) 5 5 sage: SR(5)+True; True+SR(5) 6 6 sage: SR(5)-True 4
TESTS::
sage: SR.has_coerce_map_from(SR.subring(accepting_variables=('a',))) True sage: SR.has_coerce_map_from(SR.subring(rejecting_variables=('r',))) True sage: SR.has_coerce_map_from(SR.subring(no_variables=True)) True
sage: SR.has_coerce_map_from(AA) True sage: SR.has_coerce_map_from(QQbar) True """
else:
else:
RLF, CLF, AA, QQbar, InfinityRing, UnsignedInfinityRing)
# Almost anything with a coercion into any precision of CC
def _element_constructor_(self, x): """ Coerce `x` into the symbolic expression ring SR.
EXAMPLES::
sage: a = SR(-3/4); a -3/4 sage: type(a) <type 'sage.symbolic.expression.Expression'> sage: a.parent() Symbolic Ring sage: K.<a> = QuadraticField(-3) sage: a + sin(x) I*sqrt(3) + sin(x) sage: x=var('x'); y0,y1=PolynomialRing(ZZ,2,'y').gens() sage: x+y0/y1 x + y0/y1 sage: x.subs(x=y0/y1) y0/y1 sage: x + long(1) x + 1
If `a` is already in the symbolic expression ring, coercing returns `a` itself (not a copy)::
sage: a = SR(-3/4); a -3/4 sage: SR(a) is a True
A Python complex number::
sage: SR(complex(2,-3)) (2-3j)
TESTS::
sage: SR._coerce_(int(5)) 5 sage: SR._coerce_(5) 5 sage: SR._coerce_(float(5)) 5.0 sage: SR._coerce_(5.0) 5.00000000000000
An interval arithmetic number::
sage: SR._coerce_(RIF(pi)) 3.141592653589794?
The complex number `I`::
sage: si = SR.coerce(I) sage: si^2 -1 sage: bool(si == CC.0) True
Polynomial ring element factorizations::
sage: R.<x> = QQ[] sage: SR(factor(5*x^2 - 5)) 5*(x + 1)*(x - 1) sage: R.<x,y> = QQ[] sage: SR(factor(x^2 - y^2)) (x + y)*(x - y) sage: R.<x,y,z> = QQ[] sage: SR(factor(x^2*y^3 + x^2*y^2*z - x*y^3 - x*y^2*z - 2*x*y*z - 2*x*z^2 + 2*y*z + 2*z^2)) (x*y^2 - 2*z)*(x - 1)*(y + z)
Asymptotic expansions::
sage: A.<x, y> = AsymptoticRing(growth_group='x^ZZ * y^QQ * log(y)^ZZ', coefficient_ring=ZZ) sage: s = SR(3*x^5 * log(y) + 4*y^(3/7) + O(x*log(y))); s 3*x^5*log(y) + 4*y^(3/7) + Order(x*log(y)) sage: s.operator(), s.operands() (<function add_vararg at 0x...>, [3*x^5*log(y), 4*y^(3/7), Order(x*log(y))]) sage: t = s.operands()[0]; t 3*x^5*log(y) sage: t.operator(), t.operands() (<function mul_vararg at 0x...>, [x^5, log(y), 3])
We get a sensible error message if conversion fails::
sage: SR(int) Traceback (most recent call last): ... TypeError: unable to convert <... 'int'> to a symbolic expression sage: r^(1/2) Traceback (most recent call last): ... TypeError: unable to convert R Interpreter to a symbolic expression
Check that :trac:`22068` is fixed::
sage: _ = var('x') sage: sin(x).subs(x=RR('NaN')) sin(NaN) sage: SR(RR('NaN')).is_real() False sage: sin(x).subs(x=float('NaN')) sin(NaN) sage: SR(float('NaN')).is_real() False sage: sin(x).subs(x=complex('NaN')) sin(NaN)
Check that :trac:`24072` is solved::
sage: x = polygen(GF(3)) sage: a = SR.var('a') sage: (2*x + 1) * a Traceback (most recent call last): ... TypeError: positive characteristic not allowed in symbolic computations """ cdef GEx exp return x else:
unsigned_infinity)
else:
def _force_pyobject(self, x, bint force=False, bint recursive=True): """ Wrap the given Python object in a symbolic expression even if it cannot be coerced to the Symbolic Ring.
INPUT:
- ``x`` - a Python object.
- ``force`` - bool, default ``False``, if True, the Python object is taken as is without attempting coercion or list traversal.
- ``recursive`` - bool, default ``True``, disables recursive traversal of lists.
EXAMPLES::
sage: t = SR._force_pyobject(QQ); t Rational Field sage: type(t) <type 'sage.symbolic.expression.Expression'>
Testing tuples::
sage: t = SR._force_pyobject((1, 2, x, x+1, x+2)); t (1, 2, x, x + 1, x + 2) sage: t.subs(x = 2*x^2) (1, 2, 2*x^2, 2*x^2 + 1, 2*x^2 + 2) sage: t.op[0] 1 sage: t.op[2] x
It also works if the argument is a ``list``::
sage: t = SR._force_pyobject([1, 2, x, x+1, x+2]); t (1, 2, x, x + 1, x + 2) sage: t.subs(x = 2*x^2) (1, 2, 2*x^2, 2*x^2 + 1, 2*x^2 + 2) sage: SR._force_pyobject((QQ, RR, CC)) (Rational Field, Real Field with 53 bits of precision, Complex Field with 53 bits of precision) sage: t = SR._force_pyobject((QQ, (x, x + 1, x + 2), CC)); t (Rational Field, (x, x + 1, x + 2), Complex Field with 53 bits of precision) sage: t.subs(x=x^2) (Rational Field, (x^2, x^2 + 1, x^2 + 2), Complex Field with 53 bits of precision)
If ``recursive`` is ``False`` the inner tuple is taken as a Python object. This prevents substitution as above::
sage: t = SR._force_pyobject((QQ, (x, x + 1, x + 2), CC), recursive=False) sage: t (Rational Field, (x, x + 1, x + 2), Complex Field with 53 bits of precision) sage: t.subs(x=x^2) (Rational Field, (x, x + 1, x + 2), Complex Field with 53 bits of precision) """ cdef GEx exp cdef GExprSeq ex_seq cdef GExVector ex_v
else: # first check if we can do it the nice way pass
# tuples can be packed into exprseq
else:
def wild(self, unsigned int n=0): """ Return the n-th wild-card for pattern matching and substitution.
INPUT:
- ``n`` - a nonnegative integer
OUTPUT:
- `n^{th}` wildcard expression
EXAMPLES::
sage: x,y = var('x,y') sage: w0 = SR.wild(0); w1 = SR.wild(1) sage: pattern = sin(x)*w0*w1^2; pattern $1^2*$0*sin(x) sage: f = atan(sin(x)*3*x^2); f arctan(3*x^2*sin(x)) sage: f.has(pattern) True sage: f.subs(pattern == x^2) arctan(x^2)
TESTS:
Check that :trac:`15047` is fixed::
sage: latex(SR.wild(0)) \$0
Check that :trac:`21455` is fixed::
sage: coth(SR.wild(0)) coth($0) """
def __contains__(self, x): r""" True if there is an element of the symbolic ring that is equal to x under ``==``.
EXAMPLES:
The symbolic variable x is in the symbolic ring.::
sage: x.parent() Symbolic Ring sage: x in SR True
2 is also in the symbolic ring since it is equal to something in SR, even though 2's parent is not SR.
::
sage: 2 in SR True sage: parent(2) Integer Ring sage: 1/3 in SR True """
def characteristic(self): """ Return the characteristic of the symbolic ring, which is 0.
OUTPUT:
- a Sage integer
EXAMPLES::
sage: c = SR.characteristic(); c 0 sage: type(c) <type 'sage.rings.integer.Integer'> """
def _an_element_(self): """ Return an element of the symbolic ring, which is used by the coercion model.
EXAMPLES::
sage: SR._an_element_() some_variable """
def is_field(self, proof = True): """ Returns True, since the symbolic expression ring is (for the most part) a field.
EXAMPLES::
sage: SR.is_field() True """
def is_finite(self): """ Return False, since the Symbolic Ring is infinite.
EXAMPLES::
sage: SR.is_finite() False """
cpdef bint is_exact(self) except -2: """ Return False, because there are approximate elements in the symbolic ring.
EXAMPLES::
sage: SR.is_exact() False
Here is an inexact element.
::
sage: SR(1.9393) 1.93930000000000 """
def pi(self): """ EXAMPLES::
sage: SR.pi() is pi True """
cpdef Expression symbol(self, name=None, latex_name=None, domain=None): """ EXAMPLES::
sage: t0 = SR.symbol("t0") sage: t0.conjugate() conjugate(t0)
sage: t1 = SR.symbol("t1", domain='real') sage: t1.conjugate() t1
sage: t0.abs() abs(t0)
sage: t0_2 = SR.symbol("t0", domain='positive') sage: t0_2.abs() t0 sage: bool(t0_2 == t0) True sage: t0.conjugate() t0
sage: SR.symbol() # temporary variable symbol...
We propagate the domain to the assumptions database::
sage: n = var('n', domain='integer') sage: solve([n^2 == 3],n) []
TESTS:
Test that the parent is set correctly (inheritance)::
sage: from sage.symbolic.ring import SymbolicRing sage: class MySymbolicRing(SymbolicRing): ....: def _repr_(self): ....: return 'My Symbolic Ring' sage: MySR = MySymbolicRing() sage: MySR.symbol('x').parent() My Symbolic Ring sage: MySR.var('x').parent() # indirect doctest My Symbolic Ring sage: MySR.var('blub').parent() # indirect doctest My Symbolic Ring sage: MySR.an_element().parent() My Symbolic Ring """ cdef GSymbol symb cdef Expression e
# check if there is already a symbol with same name
# fast path to get an already existing variable
# get symbol
else: # initialize a new symbol # Construct expression
symb.set_domain(sage_domain_to_ginac_domain(domain)) else: else:
def var(self, name, latex_name=None, n=None, domain=None): """ Return a symbolic variable as an element of the symbolic ring.
INPUT:
- ``name`` -- string or list of strings with the name(s) of the symbolic variable(s)
- ``latex_name`` -- (optional) string used when printing in latex mode, if not specified use ``'name'``
- ``n`` -- (optional) positive integer; number of symbolic variables, indexed from `0` to `n-1`
- ``domain`` -- (optional) specify the domain of the variable(s); it is the complex plane by default, and possible options are (non-exhaustive list, see note below): ``'real'``, ``'complex'``, ``'positive'``, ``'integer'`` and ``'noninteger'``
OUTPUT:
Symbolic expression or tuple of symbolic expressions.
.. SEEALSO::
This function does not inject the variable(s) into the global namespace. For that purpose see :meth:`var()<sage.calculus.var.var>`.
.. NOTE::
For a comprehensive list of acceptable features type ``'maxima('features')'``, and see also the documentation of :ref:`sage.symbolic.assumptions`.
EXAMPLES:
Create a variable `zz` (complex by default)::
sage: zz = SR.var('zz'); zz zz
The return type is a symbolic expression::
sage: type(zz) <type 'sage.symbolic.expression.Expression'>
We can specify the domain as well::
sage: zz = SR.var('zz', domain='real') sage: zz.is_real() True
The real domain is also set with the integer domain::
sage: SR.var('x', domain='integer').is_real() True
The ``name`` argument does not have to match the left-hand side variable::
sage: t = SR.var('theta2'); t theta2
Automatic indexing is available as well::
sage: x = SR.var('x', 4) sage: x[0], x[3] (x0, x3) sage: sum(x) x0 + x1 + x2 + x3
TESTS::
sage: var(' x y z ') (x, y, z) sage: var(' x , y , z ') (x, y, z) sage: var(' ') Traceback (most recent call last): ... ValueError: You need to specify the name of the new variable.
var(['x', 'y ', ' z ']) (x, y, z) var(['x,y']) Traceback (most recent call last): ... ValueError: The name "x,y" is not a valid Python identifier.
Check that :trac:`17206` is fixed::
sage: var1 = var('var1', latex_name=r'\sigma^2_1'); latex(var1) {\sigma^2_1}
The number of variables should be an integer greater or equal than 1::
sage: SR.var('K', -273) Traceback (most recent call last): ... ValueError: the number of variables should be a positive integer
The argument ``n`` can only handle a single variable::
sage: SR.var('x y', 4) Traceback (most recent call last): ... ValueError: cannot specify n for multiple symbol names """
else:
else: formatted_latex_name = ['{{{}}}_{{{}}}'.format(latex_name, str(i)) for i in range(n)] return tuple([self.symbol(name[i], latex_name=formatted_latex_name[i], domain=domain) for i in range(n)]) else: else: raise ValueError("cannot specify latex_name for multiple symbol names")
def _repr_element_(self, Expression x): """ Returns the string representation of the element x. This is used so that subclasses of the SymbolicRing (such the a CallableSymbolicExpressionRing) can provide their own implementations of how to print Expressions.
EXAMPLES::
sage: SR._repr_element_(x+2) 'x + 2' """
def _latex_element_(self, Expression x): """ Returns the standard LaTeX version of the expression *x*.
EXAMPLES::
sage: latex(sin(x+2)) \sin\left(x + 2\right) sage: latex(var('theta') + 2) \theta + 2 """
def _call_element_(self, _the_element, *args, **kwds): """ EXAMPLES::
sage: x,y=var('x,y') sage: f = x+y sage: f.variables() (x, y) sage: f() x + y sage: f(3) doctest:...: DeprecationWarning: Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...) See http://trac.sagemath.org/5930 for details. y + 3 sage: f(x=3) y + 3 sage: f(3,4) 7 sage: f(x=3,y=4) 7 sage: f(2,3,4) Traceback (most recent call last): ... ValueError: the number of arguments must be less than or equal to 2 sage: f(x=2,y=3,z=4) 5
::
sage: f({x:3}) y + 3 sage: f({x:3,y:4}) 7 sage: f(x=3) y + 3 sage: f(x=3,y=4) 7
::
sage: a = (2^(8/9)) sage: a(4) Traceback (most recent call last): ... ValueError: the number of arguments must be less than or equal to 0
Note that you make get unexpected results when calling symbolic expressions and not explicitly giving the variables::
sage: f = function('Gamma')(var('z'), var('w')); f Gamma(z, w) sage: f(2) Gamma(z, 2) sage: f(2,5) Gamma(5, 2)
Thus, it is better to be explicit::
sage: f(z=2) Gamma(2, w) """ else:
def subring(self, *args, **kwds): r""" Create a subring of this symbolic ring.
INPUT:
Choose one of the following keywords to create a subring.
- ``accepting_variables`` (default: ``None``) -- a tuple or other iterable of variables. If specified, then a symbolic subring of expressions in only these variables is created.
- ``rejecting_variables`` (default: ``None``) -- a tuple or other iterable of variables. If specified, then a symbolic subring of expressions in variables distinct to these variables is created.
- ``no_variables`` (default: ``False``) -- a boolean. If set, then a symbolic subring of constant expressions (i.e., expressions without a variable) is created.
OUTPUT:
A ring.
EXAMPLES:
Let us create a couple of symbolic variables first::
sage: V = var('a, b, r, s, x, y')
Now we create a symbolic subring only accepting expressions in the variables `a` and `b`::
sage: A = SR.subring(accepting_variables=(a, b)); A Symbolic Subring accepting the variables a, b
An element is ::
sage: A.an_element() a
From our variables in `V` the following are valid in `A`::
sage: tuple(v for v in V if v in A) (a, b)
Next, we create a symbolic subring rejecting expressions with given variables::
sage: R = SR.subring(rejecting_variables=(r, s)); R Symbolic Subring rejecting the variables r, s
An element is ::
sage: R.an_element() some_variable
From our variables in `V` the following are valid in `R`::
sage: tuple(v for v in V if v in R) (a, b, x, y)
We have a third kind of subring, namely the subring of symbolic constants::
sage: C = SR.subring(no_variables=True); C Symbolic Constants Subring
Note that this subring can be considered as a special accepting subring; one without any variables.
An element is ::
sage: C.an_element() I*pi*e
None of our variables in `V` is valid in `C`::
sage: tuple(v for v in V if v in C) ()
.. SEEALSO::
:doc:`subring` """ raise NotImplementedError('Cannot create subring of %s.' % (self,))
SR = SymbolicRing()
cdef unsigned sage_domain_to_ginac_domain(object domain) except? 3474701533: """ TESTS::
sage: var('x', domain='foo') Traceback (most recent call last): ... ValueError: 'foo': domain must be one of 'complex', 'real', 'positive' or 'integer' """ # convert the domain argument to something easy to parse else:
cdef void send_sage_domain_to_maxima(Expression v, object domain) except +: # convert the domain argument to something easy to parse else: raise ValueError(repr(domain)+": domain must be one of 'complex', 'real', 'positive' or 'integer'")
cdef class NumpyToSRMorphism(Morphism): r""" A morphism from numpy types to the symbolic ring.
TESTS:
We check that :trac:`8949` and :trac:`9769` are fixed (see also :trac:`18076`)::
sage: import numpy sage: f(x) = x^2 sage: f(numpy.int8('2')) 4 sage: f(numpy.int32('3')) 9
Note that the answer is a Sage integer and not a numpy type::
sage: a = f(numpy.int8('2')).pyobject() sage: type(a) <type 'sage.rings.integer.Integer'>
This behavior also applies to standard functions::
sage: cos(numpy.int('2')) cos(2) sage: numpy.cos(numpy.int('2')) -0.41614683654714241 """ cdef _intermediate_ring
def __init__(self, numpy_type): """ A Morphism which constructs Expressions from NumPy floats and complexes by converting them to elements of either RDF or CDF.
INPUT:
- ``numpy_type`` - a numpy number type
EXAMPLES::
sage: import numpy sage: from sage.symbolic.ring import NumpyToSRMorphism sage: f = NumpyToSRMorphism(numpy.float64) sage: f(numpy.float64('2.0')) 2.0 sage: _.parent() Symbolic Ring
sage: NumpyToSRMorphism(str) Traceback (most recent call last): ... TypeError: <... 'str'> is not a numpy number type """
else:
cpdef Element _call_(self, a): """ EXAMPLES:
This should be called when coercing or converting a NumPy float or complex to the Symbolic Ring::
sage: import numpy sage: SR(numpy.int32('1')).pyobject().parent() Integer Ring sage: SR(numpy.int64('-2')).pyobject().parent() Integer Ring
sage: SR(numpy.float16('1')).pyobject().parent() Real Double Field sage: SR(numpy.float64('2.0')).pyobject().parent() Real Double Field
sage: SR(numpy.complex64(1jr)).pyobject().parent() Complex Double Field """
cdef class UnderscoreSageMorphism(Morphism): def __init__(self, t, R): """ A Morphism which constructs Expressions from an arbitrary Python object by calling the :meth:`_sage_` method on the object.
EXAMPLES::
sage: import sympy sage: from sage.symbolic.ring import UnderscoreSageMorphism sage: b = sympy.var('b') sage: f = UnderscoreSageMorphism(type(b), SR) sage: f(b) b sage: _.parent() Symbolic Ring """
cpdef Element _call_(self, a): """ EXAMPLES:
This should be called when coercing or converting a SymPy object to the Symbolic Ring::
sage: import sympy sage: b = sympy.var('b') sage: bool(SR(b) == SR(b._sage_())) True """
def the_SymbolicRing(): """ Return the unique symbolic ring object.
(This is mainly used for unpickling.)
EXAMPLES::
sage: sage.symbolic.ring.the_SymbolicRing() Symbolic Ring sage: sage.symbolic.ring.the_SymbolicRing() is sage.symbolic.ring.the_SymbolicRing() True sage: sage.symbolic.ring.the_SymbolicRing() is SR True """
def is_SymbolicExpressionRing(R): """ Returns True if *R* is the symbolic expression ring.
EXAMPLES::
sage: from sage.symbolic.ring import is_SymbolicExpressionRing sage: is_SymbolicExpressionRing(ZZ) False sage: is_SymbolicExpressionRing(SR) True """
def var(name, **kwds): """ EXAMPLES::
sage: from sage.symbolic.ring import var sage: var("x y z") (x, y, z) sage: var("x,y,z") (x, y, z) sage: var("x , y , z") (x, y, z) sage: var("z") z
TESTS:
These examples test that variables can only be made from valid identifiers. See :trac:`7496` (and :trac:`9724`) for details::
sage: var(' ') Traceback (most recent call last): ... ValueError: You need to specify the name of the new variable. sage: var('3') Traceback (most recent call last): ... ValueError: The name "3" is not a valid Python identifier. """
def is_SymbolicVariable(x): """ Returns True if x is a variable.
EXAMPLES::
sage: from sage.symbolic.ring import is_SymbolicVariable sage: is_SymbolicVariable(x) True sage: is_SymbolicVariable(x+2) False
TESTS::
sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring """
def isidentifier(x): """ Return whether ``x`` is a valid identifier.
When we switch to Python 3 this function can be replaced by the official Python function of the same name.
INPUT:
- ``x`` -- a string.
OUTPUT:
Boolean. Whether the string ``x`` can be used as a variable name.
EXAMPLES::
sage: from sage.symbolic.ring import isidentifier sage: isidentifier('x') True sage: isidentifier(' x') # can't start with space False sage: isidentifier('ceci_n_est_pas_une_pipe') True sage: isidentifier('1 + x') False sage: isidentifier('2good') False sage: isidentifier('good2') True sage: isidentifier('lambda s:s+1') False """ |