Path: blob/master/sage/symbolic/expression_conversions.py
4077 views
"""1Conversion of symbolic expressions to other types23This module provides routines for converting new symbolic expressions4to other types. Primarily, it provides a class :class:`Converter`5which will walk the expression tree and make calls to methods6overridden by subclasses.7"""8###############################################################################9# Sage: Open Source Mathematical Software10# Copyright (C) 2009 Mike Hansen <[email protected]>11#12# Distributed under the terms of the GNU General Public License (GPL),13# version 2 or any later version. The full text of the GPL is available at:14# http://www.gnu.org/licenses/15###############################################################################1617import operator as _operator18from sage.symbolic.ring import SR,var19from sage.symbolic.pynac import I20from sage.functions.all import exp21from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator22from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic23GaussianField = I.pyobject().parent()2425class FakeExpression(object):26r"""27Pynac represents `x/y` as `xy^{-1}`. Often, tree-walkers would prefer28to see divisions instead of multiplications and negative exponents.29To allow for this (since Pynac internally doesn't have division at all),30there is a possibility to pass use_fake_div=True; this will rewrite31an Expression into a mixture of Expression and FakeExpression nodes,32where the FakeExpression nodes are used to represent divisions.33These nodes are intended to act sufficiently like Expression nodes34that tree-walkers won't care about the difference.35"""3637def __init__(self, operands, operator):38"""39EXAMPLES::4041sage: from sage.symbolic.expression_conversions import FakeExpression42sage: import operator; x,y = var('x,y')43sage: FakeExpression([x, y], operator.div)44FakeExpression([x, y], <built-in function div>)45"""46self._operands = operands47self._operator = operator4849def __repr__(self):50"""51EXAMPLES::5253sage: from sage.symbolic.expression_conversions import FakeExpression54sage: import operator; x,y = var('x,y')55sage: FakeExpression([x, y], operator.div)56FakeExpression([x, y], <built-in function div>)57"""58return "FakeExpression(%r, %r)"%(self._operands, self._operator)5960def pyobject(self):61"""62EXAMPLES::6364sage: from sage.symbolic.expression_conversions import FakeExpression65sage: import operator; x,y = var('x,y')66sage: f = FakeExpression([x, y], operator.div)67sage: f.pyobject()68Traceback (most recent call last):69...70TypeError: self must be a numeric expression71"""72raise TypeError, 'self must be a numeric expression'7374def operands(self):75"""76EXAMPLES::7778sage: from sage.symbolic.expression_conversions import FakeExpression79sage: import operator; x,y = var('x,y')80sage: f = FakeExpression([x, y], operator.div)81sage: f.operands()82[x, y]83"""84return self._operands8586def __getitem__(self, i):87"""88EXAMPLES::8990sage: from sage.symbolic.expression_conversions import FakeExpression91sage: import operator; x,y = var('x,y')92sage: f = FakeExpression([x, y], operator.div)93sage: f[0]94x95"""96return self._operands[i]9798def operator(self):99"""100EXAMPLES::101102sage: from sage.symbolic.expression_conversions import FakeExpression103sage: import operator; x,y = var('x,y')104sage: f = FakeExpression([x, y], operator.div)105sage: f.operator()106<built-in function div>107"""108return self._operator109110def _fast_callable_(self, etb):111"""112EXAMPLES::113114sage: from sage.symbolic.expression_conversions import FakeExpression115sage: import operator; x,y = var('x,y')116sage: f = FakeExpression([x, y], operator.div)117sage: fast_callable(f, vars=['x','y']).op_list()118[('load_arg', 0), ('load_arg', 1), 'div', 'return']119"""120return fast_callable(self, etb)121122def _fast_float_(self, *vars):123"""124EXAMPLES::125126sage: from sage.symbolic.expression_conversions import FakeExpression127sage: import operator; x,y = var('x,y')128sage: f = FakeExpression([x, y], operator.div)129sage: fast_float(f, 'x', 'y').op_list()130[('load_arg', 0), ('load_arg', 1), 'div', 'return']131"""132return fast_float(self, *vars)133134class Converter(object):135def __init__(self, use_fake_div=False):136"""137If use_fake_div is set to True, then the converter will try to138replace expressions whose operator is operator.mul with the139corresponding expression whose operator is operator.div.140141EXAMPLES::142143sage: from sage.symbolic.expression_conversions import Converter144sage: c = Converter(use_fake_div=True)145sage: c.use_fake_div146True147"""148self.use_fake_div = use_fake_div149150def __call__(self, ex=None):151"""152.. note::153154If this object does not have an attribute *ex*, then an argument155must be passed into :meth`__call__`::156157EXAMPLES::158159sage: from sage.symbolic.expression_conversions import Converter160sage: c = Converter(use_fake_div=True)161sage: c(SR(2))162Traceback (most recent call last):163...164NotImplementedError: pyobject165sage: c(x+2)166Traceback (most recent call last):167...168NotImplementedError: arithmetic169sage: c(x)170Traceback (most recent call last):171...172NotImplementedError: symbol173sage: c(x==2)174Traceback (most recent call last):175...176NotImplementedError: relation177sage: c(sin(x))178Traceback (most recent call last):179...180NotImplementedError: composition181sage: c(function('f', x).diff(x))182Traceback (most recent call last):183...184NotImplementedError: derivative185186We can set a default value for the argument by setting187the ``ex`` attribute::188189sage: c.ex = SR(2)190sage: c()191Traceback (most recent call last):192...193NotImplementedError: pyobject194"""195if ex is None:196ex = self.ex197198try:199obj = ex.pyobject()200return self.pyobject(ex, obj)201except TypeError, err:202if 'self must be a numeric expression' not in err:203raise err204205operator = ex.operator()206if operator is None:207return self.symbol(ex)208209if operator in arithmetic_operators:210if getattr(self, 'use_fake_div', False) and operator is _operator.mul:211div = self.get_fake_div(ex)212return self.arithmetic(div, div.operator())213return self.arithmetic(ex, operator)214elif operator in relation_operators:215return self.relation(ex, operator)216elif isinstance(operator, FDerivativeOperator):217return self.derivative(ex, operator)218else:219return self.composition(ex, operator)220221def get_fake_div(self, ex):222"""223EXAMPLES::224225sage: from sage.symbolic.expression_conversions import Converter226sage: c = Converter(use_fake_div=True)227sage: c.get_fake_div(sin(x)/x)228FakeExpression([sin(x), x], <built-in function div>)229sage: c.get_fake_div(-1*sin(x))230FakeExpression([sin(x)], <built-in function neg>)231sage: c.get_fake_div(-x)232FakeExpression([x], <built-in function neg>)233sage: c.get_fake_div((2*x^3+2*x-1)/((x-2)*(x+1)))234FakeExpression([2*x^3 + 2*x - 1, FakeExpression([x - 2, x + 1], <built-in function mul>)], <built-in function div>)235236Check if #8056 is fixed, i.e., if numerator is 1.::237238sage: c.get_fake_div(1/pi/x)239FakeExpression([1, FakeExpression([pi, x], <built-in function mul>)], <built-in function div>)240"""241d = []242n = []243for arg in ex.operands():244ops = arg.operands()245try:246if arg.operator() is _operator.pow and repr(ops[1]) == '-1':247d.append(ops[0])248else:249n.append(arg)250except TypeError:251n.append(arg)252253len_d = len(d)254if len_d == 0:255repr_n = map(repr, n)256if len(n) == 2 and "-1" in repr_n:257a = n[0] if repr_n[1] == "-1" else n[1]258return FakeExpression([a], _operator.neg)259else:260return ex261elif len_d == 1:262d = d[0]263else:264d = FakeExpression(d, _operator.mul)265266if len(n) == 0:267return FakeExpression([SR.one_element(), d], _operator.div)268elif len(n) == 1:269n = n[0]270else:271n = FakeExpression(n, _operator.mul)272273return FakeExpression([n,d], _operator.div)274275def pyobject(self, ex, obj):276"""277The input to this method is the result of calling278:meth:`pyobject` on a symbolic expression.279280.. note::281282Note that if a constant such as ``pi`` is encountered in283the expression tree, its corresponding pyobject which is an284instance of :class:`sage.symbolic.constants.Pi` will be285passed into this method. One cannot do arithmetic using286such an object.287288TESTS::289290sage: from sage.symbolic.expression_conversions import Converter291sage: f = SR(1)292sage: Converter().pyobject(f, f.pyobject())293Traceback (most recent call last):294...295NotImplementedError: pyobject296"""297raise NotImplementedError, "pyobject"298299def symbol(self, ex):300"""301The input to this method is a symbolic expression which302corresponds to a single variable. For example, this method303could be used to return a generator for a polynomial ring.304305TESTS::306307sage: from sage.symbolic.expression_conversions import Converter308sage: Converter().symbol(x)309Traceback (most recent call last):310...311NotImplementedError: symbol312"""313raise NotImplementedError, "symbol"314315def relation(self, ex, operator):316"""317The input to this method is a symbolic expression which318corresponds to a relation.319320TESTS::321322sage: from sage.symbolic.expression_conversions import Converter323sage: import operator324sage: Converter().relation(x==3, operator.eq)325Traceback (most recent call last):326...327NotImplementedError: relation328sage: Converter().relation(x==3, operator.lt)329Traceback (most recent call last):330...331NotImplementedError: relation332"""333raise NotImplementedError, "relation"334335def derivative(self, ex, operator):336"""337The input to this method is a symbolic expression which338corresponds to a relation.339340TESTS::341342sage: from sage.symbolic.expression_conversions import Converter343sage: a = function('f', x).diff(x); a344D[0](f)(x)345sage: Converter().derivative(a, a.operator())346Traceback (most recent call last):347...348NotImplementedError: derivative349"""350raise NotImplementedError, "derivative"351352def arithmetic(self, ex, operator):353"""354The input to this method is a symbolic expression and the355infix operator corresponding to that expression. Typically,356one will convert all of the arguments and then perform the357operation afterward.358359TESTS::360361sage: from sage.symbolic.expression_conversions import Converter362sage: f = x + 2363sage: Converter().arithmetic(f, f.operator())364Traceback (most recent call last):365...366NotImplementedError: arithmetic367"""368raise NotImplementedError, "arithmetic"369370def composition(self, ex, operator):371"""372The input to this method is a symbolic expression and its373operator. This method will get called when you have a symbolic374function application.375376TESTS::377378sage: from sage.symbolic.expression_conversions import Converter379sage: f = sin(2)380sage: Converter().composition(f, f.operator())381Traceback (most recent call last):382...383NotImplementedError: composition384"""385raise NotImplementedError, "composition"386387class InterfaceInit(Converter):388def __init__(self, interface):389"""390EXAMPLES::391392sage: from sage.symbolic.expression_conversions import InterfaceInit393sage: m = InterfaceInit(maxima)394sage: a = pi + 2395sage: m(a)396'(%pi)+(2)'397sage: m(sin(a))398'sin((%pi)+(2))'399sage: m(exp(x^2) + pi + 2)400'(%pi)+(exp((x)^(2)))+(2)'401402"""403self.name_init = "_%s_init_"%interface.name()404self.interface = interface405self.relation_symbols = interface._relation_symbols()406407def symbol(self, ex):408"""409EXAMPLES::410411sage: from sage.symbolic.expression_conversions import InterfaceInit412sage: m = InterfaceInit(maxima)413sage: m.symbol(x)414'x'415sage: f(x) = x416sage: m.symbol(f)417'x'418"""419return repr(SR(ex))420421def pyobject(self, ex, obj):422"""423EXAMPLES::424425sage: from sage.symbolic.expression_conversions import InterfaceInit426sage: ii = InterfaceInit(gp)427sage: f = 2+I428sage: ii.pyobject(f, f.pyobject())429'I + 2'430431sage: ii.pyobject(SR(2), 2)432'2'433434sage: ii.pyobject(pi, pi.pyobject())435'Pi'436"""437if (self.interface.name() in ['pari','gp'] and438isinstance(obj, NumberFieldElement_quadratic) and439obj.parent() == GaussianField):440return repr(obj)441try:442return getattr(obj, self.name_init)()443except AttributeError:444return repr(obj)445446def relation(self, ex, operator):447"""448EXAMPLES::449450sage: import operator451sage: from sage.symbolic.expression_conversions import InterfaceInit452sage: m = InterfaceInit(maxima)453sage: m.relation(x==3, operator.eq)454'x = 3'455sage: m.relation(x==3, operator.lt)456'x < 3'457"""458return "%s %s %s"%(self(ex.lhs()), self.relation_symbols[operator],459self(ex.rhs()))460461def derivative(self, ex, operator):462"""463EXAMPLES::464465sage: from sage.symbolic.expression_conversions import InterfaceInit466sage: m = InterfaceInit(maxima)467sage: f = function('f')468sage: a = f(x).diff(x); a469D[0](f)(x)470sage: print m.derivative(a, a.operator())471diff('f(x), x, 1)472sage: b = f(x).diff(x, x)473sage: print m.derivative(b, b.operator())474diff('f(x), x, 2)475476We can also convert expressions where the argument is not just a477variable, but the result is an "at" expression using temporary478variables::479480sage: y = var('y')481sage: t = (f(x*y).diff(x))/y482sage: t483D[0](f)(x*y)484sage: m.derivative(t, t.operator())485"at(diff('f(t0), t0, 1), [t0 = x*y])"486"""487#This code should probably be moved into the interface488#object in a nice way.489from sage.symbolic.ring import is_SymbolicVariable490if self.name_init != "_maxima_init_":491raise NotImplementedError492args = ex.operands()493if (not all(is_SymbolicVariable(v) for v in args) or494len(args) != len(set(args))):495# An evaluated derivative of the form f'(1) is not a496# symbolic variable, yet we would like to treat it like497# one. So, we replace the argument `1` with a temporary498# variable e.g. `t0` and then evaluate the derivative499# f'(t0) symbolically at t0=1. See trac #12796.500temp_args=[var("t%s"%i) for i in range(len(args))]501f = operator.function()502params = operator.parameter_set()503params = ["%s, %s"%(temp_args[i], params.count(i)) for i in set(params)]504subs = ["%s = %s"%(t,a) for t,a in zip(temp_args,args)]505return "at(diff('%s(%s), %s), [%s])"%(f.name(),506", ".join(map(repr,temp_args)),507", ".join(params),508", ".join(subs))509510f = operator.function()511params = operator.parameter_set()512params = ["%s, %s"%(args[i], params.count(i)) for i in set(params)]513514return "diff('%s(%s), %s)"%(f.name(),515", ".join(map(repr, args)),516", ".join(params))517518def arithmetic(self, ex, operator):519"""520EXAMPLES::521522sage: import operator523sage: from sage.symbolic.expression_conversions import InterfaceInit524sage: m = InterfaceInit(maxima)525sage: m.arithmetic(x+2, operator.add)526'(x)+(2)'527"""528args = ["(%s)"%self(op) for op in ex.operands()]529return arithmetic_operators[operator].join(args)530531def composition(self, ex, operator):532"""533EXAMPLES::534535sage: from sage.symbolic.expression_conversions import InterfaceInit536sage: m = InterfaceInit(maxima)537sage: m.composition(sin(x), sin)538'sin(x)'539sage: m.composition(ceil(x), ceil)540'ceiling(x)'541542sage: m = InterfaceInit(mathematica)543sage: m.composition(sin(x), sin)544'Sin[x]'545"""546ops = ex.operands()547#FIXME: consider stripping pyobjects() in ops548if hasattr(operator, self.name_init + "evaled_"):549return getattr(operator, self.name_init + "evaled_")(*ops)550else:551ops = map(self, ops)552try:553op = getattr(operator, self.name_init)()554except (TypeError, AttributeError):555op = repr(operator)556557return self.interface._function_call_string(op,ops,[])558559#########560# Sympy #561#########562class SympyConverter(Converter):563"""564Converts any expression to SymPy.565566EXAMPLE::567568sage: import sympy569sage: var('x,y')570(x, y)571sage: f = exp(x^2) - arcsin(pi+x)/y572sage: f._sympy_()573exp(x**2) - asin(x + pi)/y574sage: _._sage_()575-arcsin(pi + x)/y + e^(x^2)576577sage: sympy.sympify(x) # indirect doctest578x579580TESTS:581582Make sure we can convert I (trac #6424)::583584sage: bool(I._sympy_() == I)585True586sage: (x+I)._sympy_()587x + I588589"""590def pyobject(self, ex, obj):591"""592EXAMPLES::593594sage: from sage.symbolic.expression_conversions import SympyConverter595sage: s = SympyConverter()596sage: f = SR(2)597sage: s.pyobject(f, f.pyobject())5982599sage: type(_)600<class 'sympy.core.numbers.Integer'>601"""602try:603return obj._sympy_()604except AttributeError:605return obj606607def arithmetic(self, ex, operator):608"""609EXAMPLES::610611sage: from sage.symbolic.expression_conversions import SympyConverter612sage: s = SympyConverter()613sage: f = x + 2614sage: s.arithmetic(f, f.operator())615x + 2616"""617import sympy618operator = arithmetic_operators[operator]619ops = [sympy.sympify(self(a)) for a in ex.operands()]620if operator == "+":621return sympy.Add(*ops)622elif operator == "*":623return sympy.Mul(*ops)624elif operator == "-":625return sympy.Sub(*ops)626elif operator == "/":627return sympy.Div(*ops)628elif operator == "^":629return sympy.Pow(*ops)630else:631raise NotImplementedError632633def symbol(self, ex):634"""635EXAMPLES::636637sage: from sage.symbolic.expression_conversions import SympyConverter638sage: s = SympyConverter()639sage: s.symbol(x)640x641sage: type(_)642<class 'sympy.core.symbol.Symbol'>643"""644import sympy645return sympy.symbols(repr(ex))646647def composition(self, ex, operator):648"""649EXAMPLES::650651sage: from sage.symbolic.expression_conversions import SympyConverter652sage: s = SympyConverter()653sage: f = sin(2)654sage: s.composition(f, f.operator())655sin(2)656sage: type(_)657sin658sage: f = arcsin(2)659sage: s.composition(f, f.operator())660asin(2)661"""662f = operator._sympy_init_()663g = ex.operands()664import sympy665666f_sympy = getattr(sympy, f, None)667if f_sympy:668return f_sympy(*sympy.sympify(g))669else:670raise NotImplementedError("SymPy function '%s' doesn't exist" % f)671672sympy = SympyConverter()673674#############675# Algebraic #676#############677class AlgebraicConverter(Converter):678def __init__(self, field):679"""680EXAMPLES::681682sage: from sage.symbolic.expression_conversions import AlgebraicConverter683sage: a = AlgebraicConverter(QQbar)684sage: a.field685Algebraic Field686sage: a.reciprocal_trig_functions['cot']687tan688"""689self.field = field690691from sage.functions.all import reciprocal_trig_functions692self.reciprocal_trig_functions = reciprocal_trig_functions693694def pyobject(self, ex, obj):695"""696EXAMPLES::697698sage: from sage.symbolic.expression_conversions import AlgebraicConverter699sage: a = AlgebraicConverter(QQbar)700sage: f = SR(2)701sage: a.pyobject(f, f.pyobject())7022703sage: _.parent()704Algebraic Field705"""706return self.field(obj)707708def arithmetic(self, ex, operator):709"""710Convert a symbolic expression to an algebraic number.711712EXAMPLES::713714sage: from sage.symbolic.expression_conversions import AlgebraicConverter715sage: f = 2^(1/2)716sage: a = AlgebraicConverter(QQbar)717sage: a.arithmetic(f, f.operator())7181.414213562373095?719720TESTS::721722sage: f = pi^6723sage: a = AlgebraicConverter(QQbar)724sage: a.arithmetic(f, f.operator())725Traceback (most recent call last):726...727TypeError: unable to convert pi^6 to Algebraic Field728"""729# We try to avoid simplifying, because maxima's simplify command730# can change the value of a radical expression (by changing which731# root is selected).732try:733if operator is _operator.pow:734from sage.rings.all import Rational735base, expt = ex.operands()736base = self.field(base)737expt = Rational(expt)738return self.field(base**expt)739else:740return reduce(operator, map(self, ex.operands()))741except TypeError:742pass743744if operator is _operator.pow:745from sage.symbolic.constants import e, pi, I746base, expt = ex.operands()747if base == e and expt / (pi*I) in QQ:748return exp(expt)._algebraic_(self.field)749750raise TypeError, "unable to convert %s to %s"%(ex, self.field)751752def composition(self, ex, operator):753"""754Coerce to an algebraic number.755756EXAMPLES::757758sage: from sage.symbolic.expression_conversions import AlgebraicConverter759sage: a = AlgebraicConverter(QQbar)760sage: a.composition(exp(I*pi/3), exp)7610.500000000000000? + 0.866025403784439?*I762sage: a.composition(sin(pi/5), sin)7630.5877852522924731? + 0.?e-18*I764765TESTS::766767sage: QQbar(zeta(7))768Traceback (most recent call last):769...770TypeError: unable to convert zeta(7) to Algebraic Field771"""772func = operator773operand, = ex.operands()774775QQbar = self.field.algebraic_closure()776# Note that comparing functions themselves goes via maxima, and is SLOW777func_name = repr(func)778if func_name == 'exp':779rat_arg = (operand.imag()/(2*ex.parent().pi()))._rational_()780if rat_arg == 0:781# here we will either try and simplify, or return782raise ValueError, "Unable to represent as an algebraic number."783real = operand.real()784if real:785mag = exp(operand.real())._algebraic_(QQbar)786else:787mag = 1788res = mag * QQbar.zeta(rat_arg.denom())**rat_arg.numer()789elif func_name in ['sin', 'cos', 'tan']:790exp_ia = exp(SR(-1).sqrt()*operand)._algebraic_(QQbar)791if func_name == 'sin':792res = (exp_ia - ~exp_ia)/(2*QQbar.zeta(4))793elif func_name == 'cos':794res = (exp_ia + ~exp_ia)/2795else:796res = -QQbar.zeta(4)*(exp_ia - ~exp_ia)/(exp_ia + ~exp_ia)797elif func_name in ['sinh', 'cosh', 'tanh']:798exp_a = exp(operand)._algebraic_(QQbar)799if func_name == 'sinh':800res = (exp_a - ~exp_a)/2801elif func_name == 'cosh':802res = (exp_a + ~exp_a)/2803else:804res = (exp_a - ~exp_a) / (exp_a + ~exp_a)805elif func_name in self.reciprocal_trig_functions:806res = ~self.reciprocal_trig_functions[func_name](operand)._algebraic_(QQbar)807else:808res = func(operand._algebraic_(self.field))809#We have to handle the case where we get the same symbolic810#expression back. For example, QQbar(zeta(7)). See811#ticket #12665.812if cmp(res, ex) == 0:813raise TypeError, "unable to convert %s to %s"%(ex, self.field)814return self.field(res)815816def algebraic(ex, field):817"""818Returns the symbolic expression *ex* as a element of the algebraic819field *field*.820821EXAMPLES::822823sage: a = SR(5/6)824sage: AA(a)8255/6826sage: type(AA(a))827<class 'sage.rings.qqbar.AlgebraicReal'>828sage: QQbar(a)8295/6830sage: type(QQbar(a))831<class 'sage.rings.qqbar.AlgebraicNumber'>832sage: QQbar(i)8331*I834sage: AA(golden_ratio)8351.618033988749895?836sage: QQbar(golden_ratio)8371.618033988749895?838sage: QQbar(sin(pi/3))8390.866025403784439?840841sage: QQbar(sqrt(2) + sqrt(8))8424.242640687119285?843sage: AA(sqrt(2) ^ 4) == 4844True845sage: AA(-golden_ratio)846-1.618033988749895?847sage: QQbar((2*I)^(1/2))8481 + 1*I849sage: QQbar(e^(pi*I/3))8500.500000000000000? + 0.866025403784439?*I851852sage: AA(x*sin(0))8530854sage: QQbar(x*sin(0))8550856"""857return AlgebraicConverter(field)(ex)858859##############860# Polynomial #861##############862class PolynomialConverter(Converter):863def __init__(self, ex, base_ring=None, ring=None):864"""865EXAMPLES::866867sage: from sage.symbolic.expression_conversions import PolynomialConverter868sage: x, y = var('x,y')869sage: p = PolynomialConverter(x+y, base_ring=QQ)870sage: p.base_ring871Rational Field872sage: p.ring873Multivariate Polynomial Ring in x, y over Rational Field874875sage: p = PolynomialConverter(x, base_ring=QQ)876sage: p.base_ring877Rational Field878sage: p.ring879Univariate Polynomial Ring in x over Rational Field880881sage: p = PolynomialConverter(x, ring=QQ['x,y'])882sage: p.base_ring883Rational Field884sage: p.ring885Multivariate Polynomial Ring in x, y over Rational Field886887sage: p = PolynomialConverter(x+y, ring=QQ['x'])888Traceback (most recent call last):889...890TypeError: y is not a variable of Univariate Polynomial Ring in x over Rational Field891892893"""894if not (ring is None or base_ring is None):895raise TypeError, "either base_ring or ring must be specified, but not both"896self.ex = ex897898if ring is not None:899base_ring = ring.base_ring()900G = ring.variable_names_recursive()901for v in ex.variables():902if repr(v) not in G and v not in base_ring:903raise TypeError, "%s is not a variable of %s" %(v, ring)904self.ring = ring905self.base_ring = base_ring906elif base_ring is not None:907self.base_ring = base_ring908vars = self.ex.variables()909if len(vars) == 0:910vars = ['x']911from sage.rings.all import PolynomialRing912self.ring = PolynomialRing(self.base_ring, names=vars)913else:914raise TypeError, "either a ring or base ring must be specified"915916def symbol(self, ex):917"""918Returns a variable in the polynomial ring.919920EXAMPLES::921922sage: from sage.symbolic.expression_conversions import PolynomialConverter923sage: p = PolynomialConverter(x, base_ring=QQ)924sage: p.symbol(x)925x926sage: _.parent()927Univariate Polynomial Ring in x over Rational Field928"""929return self.ring(repr(ex))930931def pyobject(self, ex, obj):932"""933EXAMPLES::934935sage: from sage.symbolic.expression_conversions import PolynomialConverter936sage: p = PolynomialConverter(x, base_ring=QQ)937sage: f = SR(2)938sage: p.pyobject(f, f.pyobject())9392940sage: _.parent()941Rational Field942"""943return self.base_ring(obj)944945def composition(self, ex, operator):946"""947EXAMPLES::948949sage: from sage.symbolic.expression_conversions import PolynomialConverter950sage: a = sin(2)951sage: p = PolynomialConverter(a*x, base_ring=RR)952sage: p.composition(a, a.operator())9530.909297426825682954"""955return self.base_ring(ex)956957def relation(self, ex, op):958"""959EXAMPLES::960961sage: import operator962sage: from sage.symbolic.expression_conversions import PolynomialConverter963964sage: x, y = var('x, y')965sage: p = PolynomialConverter(x, base_ring=RR)966967sage: p.relation(x==3, operator.eq)968x - 3.00000000000000969sage: p.relation(x==3, operator.lt)970Traceback (most recent call last):971...972ValueError: Unable to represent as a polynomial973974sage: p = PolynomialConverter(x - y, base_ring=QQ)975sage: p.relation(x^2 - y^3 + 1 == x^3, operator.eq)976-x^3 - y^3 + x^2 + 1977"""978import operator979if op == operator.eq:980return self(ex.lhs()) - self(ex.rhs())981else:982raise ValueError, "Unable to represent as a polynomial"983984def arithmetic(self, ex, operator):985"""986EXAMPLES::987988sage: import operator989sage: from sage.symbolic.expression_conversions import PolynomialConverter990991sage: x, y = var('x, y')992sage: p = PolynomialConverter(x, base_ring=RR)993sage: p.arithmetic(pi+e, operator.add)9945.85987448204884995sage: p.arithmetic(x^2, operator.pow)996x^2997998sage: p = PolynomialConverter(x+y, base_ring=RR)999sage: p.arithmetic(x*y+y^2, operator.add)1000x*y + y^21001"""1002if len(ex.variables()) == 0:1003return self.base_ring(ex)1004elif operator == _operator.pow:1005from sage.rings.all import Integer1006base, exp = ex.operands()1007return self(base)**Integer(exp)1008else:1009ops = [self(a) for a in ex.operands()]1010return reduce(operator, ops)10111012def polynomial(ex, base_ring=None, ring=None):1013"""1014Returns a polynomial from the symbolic expression *ex*. Either a1015base ring *base_ring* or a polynomial ring *ring* can be specified1016for the parent of result. If just a base ring is given, then the variables1017of the base ring will be the variables of the expression *ex*.10181019EXAMPLES::10201021sage: from sage.symbolic.expression_conversions import polynomial1022sage: f = x^2 + 21023sage: polynomial(f, base_ring=QQ)1024x^2 + 21025sage: _.parent()1026Univariate Polynomial Ring in x over Rational Field10271028sage: polynomial(f, ring=QQ['x,y'])1029x^2 + 21030sage: _.parent()1031Multivariate Polynomial Ring in x, y over Rational Field10321033sage: x, y = var('x, y')1034sage: polynomial(x + y^2, ring=QQ['x,y'])1035y^2 + x1036sage: _.parent()1037Multivariate Polynomial Ring in x, y over Rational Field10381039sage: s,t=var('s,t')1040sage: expr=t^2-2*s*t+11041sage: expr.polynomial(None,ring=SR['t'])1042t^2 - 2*s*t + 11043sage: _.parent()1044Univariate Polynomial Ring in t over Symbolic Ring1045104610471048The polynomials can have arbitrary (constant) coefficients so long as1049they coerce into the base ring::10501051sage: polynomial(2^sin(2)*x^2 + exp(3), base_ring=RR)10521.87813065119873*x^2 + 20.08553692318771053"""1054converter = PolynomialConverter(ex, base_ring=base_ring, ring=ring)1055res = converter()1056return converter.ring(res)10571058##############1059# Fast Float #1060##############10611062class FastFloatConverter(Converter):1063def __init__(self, ex, *vars):1064"""1065Returns an object which provides fast floating point1066evaluation of the symbolic expression *ex*. This is an class1067used internally and is not meant to be used directly.10681069See :mod:`sage.ext.fast_eval` for more information.10701071EXAMPLES::10721073sage: x,y,z = var('x,y,z')1074sage: f = 1 + sin(x)/x + sqrt(z^2+y^2)/cosh(x)1075sage: ff = f._fast_float_('x', 'y', 'z')1076sage: f(x=1.0,y=2.0,z=3.0).n()10774.1780638977...1078sage: ff(1.0,2.0,3.0)10794.1780638977...10801081Using _fast_float_ without specifying the variable names is1082deprecated::10831084sage: f = x._fast_float_()1085doctest:...: 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=...)1086sage: f(1.2)10871.210881089Using _fast_float_ on a function which is the identity is1090now supported (see Trac 10246)::10911092sage: f = symbolic_expression(x).function(x)1093sage: f._fast_float_(x)1094<sage.ext.fast_eval.FastDoubleFunc object at ...>1095sage: f(22)1096221097"""1098self.ex = ex10991100if vars == ():1101try:1102vars = ex.arguments()1103except AttributeError:1104vars = ex.variables()11051106if vars:1107from sage.misc.misc import deprecation1108deprecation("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=...)")110911101111self.vars = vars11121113import sage.ext.fast_eval as fast_float1114self.ff = fast_float11151116Converter.__init__(self, use_fake_div=True)11171118def relation(self, ex, operator):1119"""1120EXAMPLES::11211122sage: ff = fast_float(x == 2, 'x')1123sage: ff(2)11240.01125sage: ff(4)11262.01127sage: ff = fast_float(x < 2, 'x')1128Traceback (most recent call last):1129...1130NotImplementedError1131"""1132if operator is not _operator.eq:1133raise NotImplementedError1134return self(ex.lhs() - ex.rhs())11351136def pyobject(self, ex, obj):1137"""1138EXAMPLES::11391140sage: f = SR(2)._fast_float_()1141sage: f(3)11422.01143"""1144try:1145return obj._fast_float_(*self.vars)1146except AttributeError:1147return self.ff.fast_float_constant(float(obj))11481149def symbol(self, ex):1150r"""1151EXAMPLES::11521153sage: f = x._fast_float_('x', 'y')1154sage: f(1,2)11551.01156sage: f = x._fast_float_('y', 'x')1157sage: f(1,2)11582.01159"""1160if self.vars == ():1161return self.ff.fast_float_arg(0)11621163vars = list(self.vars)1164name = repr(ex)1165if name in vars:1166return self.ff.fast_float_arg(vars.index(name))1167svars = [repr(x) for x in vars]1168if name in svars:1169return self.ff.fast_float_arg(svars.index(name))11701171if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x1172name = repr(SR(ex)) # this gets back just the 'output' of the function1173if name in svars:1174return self.ff.fast_float_arg(svars.index(name))11751176try:1177return self.ff.fast_float_constant(float(ex))1178except TypeError:1179raise ValueError, "free variable: %s" % repr(ex)11801181def arithmetic(self, ex, operator):1182"""1183EXAMPLES::11841185sage: x,y = var('x,y')1186sage: f = x*x-y1187sage: ff = f._fast_float_('x','y')1188sage: ff(2,3)11891.011901191sage: a = x + 2*y1192sage: f = a._fast_float_('x', 'y')1193sage: f(1,0)11941.01195sage: f(0,1)11962.011971198sage: f = sqrt(x)._fast_float_('x'); f.op_list()1199['load 0', 'call sqrt(1)']12001201sage: f = (1/2*x)._fast_float_('x'); f.op_list()1202['load 0', 'push 0.5', 'mul']1203"""1204operands = ex.operands()1205if operator is _operator.neg:1206return operator(self(operands[0]))12071208from sage.rings.all import Rational1209if operator is _operator.pow and operands[1] == Rational(((1,2))):1210from sage.functions.all import sqrt1211return sqrt(self(operands[0]))1212fops = map(self, operands)1213return reduce(operator, fops)12141215def composition(self, ex, operator):1216"""1217EXAMPLES::12181219sage: f = sqrt(x)._fast_float_('x')1220sage: f(2)12211.41421356237309...1222sage: y = var('y')1223sage: f = sqrt(x+y)._fast_float_('x', 'y')1224sage: f(1,1)12251.41421356237309...12261227::12281229sage: f = sqrt(x+2*y)._fast_float_('x', 'y')1230sage: f(2,0)12311.41421356237309...1232sage: f(0,1)12331.41421356237309...1234"""1235f = operator1236g = map(self, ex.operands())1237try:1238return f(*g)1239except TypeError:1240from sage.functions.other import abs_symbolic1241if f is abs_symbolic:1242return abs(*g) # special case1243else:1244return self.ff.fast_float_func(f, *g)12451246def fast_float(ex, *vars):1247"""1248Returns an object which provides fast floating point evaluation of1249the symbolic expression *ex*.12501251See :mod:`sage.ext.fast_eval` for more information.12521253EXAMPLES::12541255sage: from sage.symbolic.expression_conversions import fast_float1256sage: f = sqrt(x+1)1257sage: ff = fast_float(f, 'x')1258sage: ff(1.0)12591.41421356237309511260"""1261return FastFloatConverter(ex, *vars)()12621263#################1264# Fast Callable #1265#################12661267class FastCallableConverter(Converter):1268def __init__(self, ex, etb):1269"""1270EXAMPLES::12711272sage: from sage.symbolic.expression_conversions import FastCallableConverter1273sage: from sage.ext.fast_callable import ExpressionTreeBuilder1274sage: etb = ExpressionTreeBuilder(vars=['x'])1275sage: f = FastCallableConverter(x+2, etb)1276sage: f.ex1277x + 21278sage: f.etb1279<sage.ext.fast_callable.ExpressionTreeBuilder object at 0x...>1280sage: f.use_fake_div1281True1282"""1283self.ex = ex1284self.etb = etb1285Converter.__init__(self, use_fake_div=True)12861287def pyobject(self, ex, obj):1288r"""1289EXAMPLES::12901291sage: from sage.ext.fast_callable import ExpressionTreeBuilder1292sage: etb = ExpressionTreeBuilder(vars=['x'])1293sage: pi._fast_callable_(etb)1294pi1295sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)1296sage: pi._fast_callable_(etb)12973.141592653591298"""1299from sage.symbolic.constants import Constant1300if isinstance(obj, Constant):1301obj = obj.expression()1302return self.etb.constant(obj)13031304def relation(self, ex, operator):1305"""1306EXAMPLES::13071308sage: ff = fast_callable(x == 2, vars=['x'])1309sage: ff(2)131001311sage: ff(4)131221313sage: ff = fast_callable(x < 2, vars=['x'])1314Traceback (most recent call last):1315...1316NotImplementedError1317"""1318if operator is not _operator.eq:1319raise NotImplementedError1320return self(ex.lhs() - ex.rhs())13211322def arithmetic(self, ex, operator):1323r"""1324EXAMPLES::13251326sage: from sage.ext.fast_callable import ExpressionTreeBuilder1327sage: etb = ExpressionTreeBuilder(vars=['x','y'])1328sage: var('x,y')1329(x, y)1330sage: (x+y)._fast_callable_(etb)1331add(v_0, v_1)1332sage: (-x)._fast_callable_(etb)1333neg(v_0)1334sage: (x+y+x^2)._fast_callable_(etb)1335add(add(ipow(v_0, 2), v_0), v_1)13361337TESTS:13381339Check if rational functions with numerator 1 can be converted. #8056::13401341sage: (1/pi/x)._fast_callable_(etb)1342div(1, mul(pi, v_0))13431344sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)1345sage: (x^7)._fast_callable_(etb)1346ipow(v_0, 7)1347sage: f(x)=1/pi/x; plot(f,2,3)1348"""1349# This used to convert the operands first. Doing it this way1350# instead gives a chance to notice powers with an integer1351# exponent before the exponent gets (potentially) converted1352# to another type.1353operands = ex.operands()1354if operator is _operator.pow:1355exponent = operands[1]1356if exponent == -1:1357return self.etb.call(_operator.div, 1, operands[0])1358elif exponent == 0.5:1359from sage.functions.all import sqrt1360return self.etb.call(sqrt, operands[0])1361elif exponent == -0.5:1362from sage.functions.all import sqrt1363return self.etb.call(_operator.div, 1, self.etb.call(sqrt, operands[0]))1364elif operator is _operator.neg:1365return self.etb.call(operator, operands[0])1366return reduce(lambda x,y: self.etb.call(operator, x,y), operands)13671368def symbol(self, ex):1369r"""1370Given an ExpressionTreeBuilder, return an Expression representing1371this value.13721373EXAMPLES::13741375sage: from sage.ext.fast_callable import ExpressionTreeBuilder1376sage: etb = ExpressionTreeBuilder(vars=['x','y'])1377sage: x, y, z = var('x,y,z')1378sage: x._fast_callable_(etb)1379v_01380sage: y._fast_callable_(etb)1381v_11382sage: z._fast_callable_(etb)1383Traceback (most recent call last):1384...1385ValueError: Variable 'z' not found1386"""1387return self.etb.var(SR(ex))13881389def composition(self, ex, function):1390r"""1391Given an ExpressionTreeBuilder, return an Expression representing1392this value.13931394EXAMPLES::13951396sage: from sage.ext.fast_callable import ExpressionTreeBuilder1397sage: etb = ExpressionTreeBuilder(vars=['x','y'])1398sage: x,y = var('x,y')1399sage: sin(sqrt(x+y))._fast_callable_(etb)1400sin(sqrt(add(v_0, v_1)))1401sage: arctan2(x,y)._fast_callable_(etb)1402{arctan2}(v_0, v_1)1403"""1404return self.etb.call(function, *ex.operands())140514061407def fast_callable(ex, etb):1408"""1409Given an ExpressionTreeBuilder *etb*, return an Expression representing1410the symbolic expression *ex*.14111412EXAMPLES::14131414sage: from sage.ext.fast_callable import ExpressionTreeBuilder1415sage: etb = ExpressionTreeBuilder(vars=['x','y'])1416sage: x,y = var('x,y')1417sage: f = y+2*x^21418sage: f._fast_callable_(etb)1419add(mul(ipow(v_0, 2), 2), v_1)14201421sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))1422sage: f._fast_callable_(etb)1423div(add(add(mul(ipow(v_0, 3), 2), mul(v_0, 2)), -1), mul(add(v_0, -2), add(v_0, 1)))14241425"""1426return FastCallableConverter(ex, etb)()14271428class RingConverter(Converter):1429def __init__(self, R, subs_dict=None):1430"""1431A class to convert expressions to other rings.14321433EXAMPLES::14341435sage: from sage.symbolic.expression_conversions import RingConverter1436sage: R = RingConverter(RIF, subs_dict={x:2})1437sage: R.ring1438Real Interval Field with 53 bits of precision1439sage: R.subs_dict1440{x: 2}1441sage: R(pi+e)14425.85987448204884?1443sage: loads(dumps(R))1444<sage.symbolic.expression_conversions.RingConverter object at 0x...>1445"""1446self.subs_dict = {} if subs_dict is None else subs_dict1447self.ring = R14481449def symbol(self, ex):1450"""1451All symbols appearing in the expression must appear in *subs_dict*1452in order for the conversion to be successful.14531454EXAMPLES::14551456sage: from sage.symbolic.expression_conversions import RingConverter1457sage: R = RingConverter(RIF, subs_dict={x:2})1458sage: R(x+pi)14595.141592653589794?14601461sage: R = RingConverter(RIF)1462sage: R(x+pi)1463Traceback (most recent call last):1464...1465TypeError1466"""1467try:1468return self.ring(self.subs_dict[ex])1469except KeyError:1470raise TypeError14711472def pyobject(self, ex, obj):1473"""1474EXAMPLES::14751476sage: from sage.symbolic.expression_conversions import RingConverter1477sage: R = RingConverter(RIF)1478sage: R(SR(5/2))14792.5000000000000000?1480"""1481return self.ring(obj)14821483def arithmetic(self, ex, operator):1484"""1485EXAMPLES::14861487sage: from sage.symbolic.expression_conversions import RingConverter1488sage: P.<z> = ZZ[]1489sage: R = RingConverter(P, subs_dict={x:z})1490sage: a = 2*x^2 + x + 31491sage: R(a)14922*z^2 + z + 31493"""1494if operator not in [_operator.add, _operator.mul, _operator.pow]:1495raise TypeError14961497operands = ex.operands()1498if operator is _operator.pow:1499from sage.all import Integer, Rational1500base, expt = operands15011502if expt == Rational(((1,2))):1503from sage.functions.all import sqrt1504return sqrt(self(base))1505try:1506expt = Integer(expt)1507except TypeError:1508pass15091510base = self(base)1511return base ** expt1512else:1513return reduce(operator, map(self, operands))15141515def composition(self, ex, operator):1516"""1517EXAMPLES::15181519sage: from sage.symbolic.expression_conversions import RingConverter1520sage: R = RingConverter(RIF)1521sage: R(cos(2))1522-0.4161468365471424?1523"""1524res = operator(*map(self, ex.operands()))1525if res.parent() is not self.ring:1526raise TypeError1527else:1528return res15291530class SubstituteFunction(Converter):1531def __init__(self, ex, original, new):1532"""1533A class that walks the tree and replaces occurrences of a1534function with another.15351536EXAMPLES::15371538sage: from sage.symbolic.expression_conversions import SubstituteFunction1539sage: foo = function('foo'); bar = function('bar')1540sage: s = SubstituteFunction(foo(x), foo, bar)1541sage: s(1/foo(foo(x)) + foo(2))15421/bar(bar(x)) + bar(2)1543"""1544self.original = original1545self.new = new1546self.ex = ex15471548def symbol(self, ex):1549"""1550EXAMPLES::15511552sage: from sage.symbolic.expression_conversions import SubstituteFunction1553sage: foo = function('foo'); bar = function('bar')1554sage: s = SubstituteFunction(foo(x), foo, bar)1555sage: s.symbol(x)1556x1557"""1558return ex15591560def pyobject(self, ex, obj):1561"""1562EXAMPLES::15631564sage: from sage.symbolic.expression_conversions import SubstituteFunction1565sage: foo = function('foo'); bar = function('bar')1566sage: s = SubstituteFunction(foo(x), foo, bar)1567sage: f = SR(2)1568sage: s.pyobject(f, f.pyobject())156921570sage: _.parent()1571Symbolic Ring1572"""1573return ex15741575def relation(self, ex, operator):1576"""1577EXAMPLES::15781579sage: from sage.symbolic.expression_conversions import SubstituteFunction1580sage: foo = function('foo'); bar = function('bar')1581sage: s = SubstituteFunction(foo(x), foo, bar)1582sage: eq = foo(x) == x1583sage: s.relation(eq, eq.operator())1584bar(x) == x1585"""1586return operator(self(ex.lhs()), self(ex.rhs()))15871588def arithmetic(self, ex, operator):1589"""1590EXAMPLES::15911592sage: from sage.symbolic.expression_conversions import SubstituteFunction1593sage: foo = function('foo'); bar = function('bar')1594sage: s = SubstituteFunction(foo(x), foo, bar)1595sage: f = x*foo(x) + pi/foo(x)1596sage: s.arithmetic(f, f.operator())1597x*bar(x) + pi/bar(x)1598"""1599return reduce(operator, map(self, ex.operands()))16001601def composition(self, ex, operator):1602"""1603EXAMPLES::16041605sage: from sage.symbolic.expression_conversions import SubstituteFunction1606sage: foo = function('foo'); bar = function('bar')1607sage: s = SubstituteFunction(foo(x), foo, bar)1608sage: f = foo(x)1609sage: s.composition(f, f.operator())1610bar(x)1611sage: f = foo(foo(x))1612sage: s.composition(f, f.operator())1613bar(bar(x))1614sage: f = sin(foo(x))1615sage: s.composition(f, f.operator())1616sin(bar(x))1617sage: f = foo(sin(x))1618sage: s.composition(f, f.operator())1619bar(sin(x))1620"""1621if operator == self.original:1622return self.new(*map(self, ex.operands()))1623else:1624return operator(*map(self, ex.operands()))16251626def derivative(self, ex, operator):1627"""1628EXAMPLES::16291630sage: from sage.symbolic.expression_conversions import SubstituteFunction1631sage: foo = function('foo'); bar = function('bar')1632sage: s = SubstituteFunction(foo(x), foo, bar)1633sage: f = foo(x).diff(x)1634sage: s.derivative(f, f.operator())1635D[0](bar)(x)16361637TESTS:16381639We can substitute functions under a derivative operator,1640:trac:`12801`::16411642sage: f = function('f')1643sage: g = function('g')1644sage: f(g(x)).diff(x).substitute_function(g, sin)1645cos(x)*D[0](f)(sin(x))16461647"""1648if operator.function() == self.original:1649return operator.change_function(self.new)(*map(self,ex.operands()))1650else:1651return operator(*map(self, ex.operands()))165216531654