Path: blob/master/src/sage/symbolic/expression_conversions.py
8817 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 + 1, x - 2], <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 using1086function-call syntax and unnamed arguments is deprecated1087and will be removed from a future release of Sage; you1088can use named arguments instead, like EXPR(x=..., y=...)1089See http://trac.sagemath.org/5930 for details.1090sage: f(1.2)10911.210921093Using _fast_float_ on a function which is the identity is1094now supported (see Trac 10246)::10951096sage: f = symbolic_expression(x).function(x)1097sage: f._fast_float_(x)1098<sage.ext.fast_eval.FastDoubleFunc object at ...>1099sage: f(22)1100221101"""1102self.ex = ex11031104if vars == ():1105try:1106vars = ex.arguments()1107except AttributeError:1108vars = ex.variables()11091110if vars:1111from sage.misc.superseded import deprecation1112deprecation(5930, "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=...)")111311141115self.vars = vars11161117import sage.ext.fast_eval as fast_float1118self.ff = fast_float11191120Converter.__init__(self, use_fake_div=True)11211122def relation(self, ex, operator):1123"""1124EXAMPLES::11251126sage: ff = fast_float(x == 2, 'x')1127sage: ff(2)11280.01129sage: ff(4)11302.01131sage: ff = fast_float(x < 2, 'x')1132Traceback (most recent call last):1133...1134NotImplementedError1135"""1136if operator is not _operator.eq:1137raise NotImplementedError1138return self(ex.lhs() - ex.rhs())11391140def pyobject(self, ex, obj):1141"""1142EXAMPLES::11431144sage: f = SR(2)._fast_float_()1145sage: f(3)11462.01147"""1148try:1149return obj._fast_float_(*self.vars)1150except AttributeError:1151return self.ff.fast_float_constant(float(obj))11521153def symbol(self, ex):1154r"""1155EXAMPLES::11561157sage: f = x._fast_float_('x', 'y')1158sage: f(1,2)11591.01160sage: f = x._fast_float_('y', 'x')1161sage: f(1,2)11622.01163"""1164if self.vars == ():1165return self.ff.fast_float_arg(0)11661167vars = list(self.vars)1168name = repr(ex)1169if name in vars:1170return self.ff.fast_float_arg(vars.index(name))1171svars = [repr(x) for x in vars]1172if name in svars:1173return self.ff.fast_float_arg(svars.index(name))11741175if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x1176name = repr(SR(ex)) # this gets back just the 'output' of the function1177if name in svars:1178return self.ff.fast_float_arg(svars.index(name))11791180try:1181return self.ff.fast_float_constant(float(ex))1182except TypeError:1183raise ValueError, "free variable: %s" % repr(ex)11841185def arithmetic(self, ex, operator):1186"""1187EXAMPLES::11881189sage: x,y = var('x,y')1190sage: f = x*x-y1191sage: ff = f._fast_float_('x','y')1192sage: ff(2,3)11931.011941195sage: a = x + 2*y1196sage: f = a._fast_float_('x', 'y')1197sage: f(1,0)11981.01199sage: f(0,1)12002.012011202sage: f = sqrt(x)._fast_float_('x'); f.op_list()1203['load 0', 'call sqrt(1)']12041205sage: f = (1/2*x)._fast_float_('x'); f.op_list()1206['load 0', 'push 0.5', 'mul']1207"""1208operands = ex.operands()1209if operator is _operator.neg:1210return operator(self(operands[0]))12111212from sage.rings.all import Rational1213if operator is _operator.pow and operands[1] == Rational(((1,2))):1214from sage.functions.all import sqrt1215return sqrt(self(operands[0]))1216fops = map(self, operands)1217return reduce(operator, fops)12181219def composition(self, ex, operator):1220"""1221EXAMPLES::12221223sage: f = sqrt(x)._fast_float_('x')1224sage: f(2)12251.41421356237309...1226sage: y = var('y')1227sage: f = sqrt(x+y)._fast_float_('x', 'y')1228sage: f(1,1)12291.41421356237309...12301231::12321233sage: f = sqrt(x+2*y)._fast_float_('x', 'y')1234sage: f(2,0)12351.41421356237309...1236sage: f(0,1)12371.41421356237309...1238"""1239f = operator1240g = map(self, ex.operands())1241try:1242return f(*g)1243except TypeError:1244from sage.functions.other import abs_symbolic1245if f is abs_symbolic:1246return abs(*g) # special case1247else:1248return self.ff.fast_float_func(f, *g)12491250def fast_float(ex, *vars):1251"""1252Returns an object which provides fast floating point evaluation of1253the symbolic expression *ex*.12541255See :mod:`sage.ext.fast_eval` for more information.12561257EXAMPLES::12581259sage: from sage.symbolic.expression_conversions import fast_float1260sage: f = sqrt(x+1)1261sage: ff = fast_float(f, 'x')1262sage: ff(1.0)12631.41421356237309511264"""1265return FastFloatConverter(ex, *vars)()12661267#################1268# Fast Callable #1269#################12701271class FastCallableConverter(Converter):1272def __init__(self, ex, etb):1273"""1274EXAMPLES::12751276sage: from sage.symbolic.expression_conversions import FastCallableConverter1277sage: from sage.ext.fast_callable import ExpressionTreeBuilder1278sage: etb = ExpressionTreeBuilder(vars=['x'])1279sage: f = FastCallableConverter(x+2, etb)1280sage: f.ex1281x + 21282sage: f.etb1283<sage.ext.fast_callable.ExpressionTreeBuilder object at 0x...>1284sage: f.use_fake_div1285True1286"""1287self.ex = ex1288self.etb = etb1289Converter.__init__(self, use_fake_div=True)12901291def pyobject(self, ex, obj):1292r"""1293EXAMPLES::12941295sage: from sage.ext.fast_callable import ExpressionTreeBuilder1296sage: etb = ExpressionTreeBuilder(vars=['x'])1297sage: pi._fast_callable_(etb)1298pi1299sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)1300sage: pi._fast_callable_(etb)13013.141592653591302"""1303from sage.symbolic.constants import Constant1304if isinstance(obj, Constant):1305obj = obj.expression()1306return self.etb.constant(obj)13071308def relation(self, ex, operator):1309"""1310EXAMPLES::13111312sage: ff = fast_callable(x == 2, vars=['x'])1313sage: ff(2)131401315sage: ff(4)131621317sage: ff = fast_callable(x < 2, vars=['x'])1318Traceback (most recent call last):1319...1320NotImplementedError1321"""1322if operator is not _operator.eq:1323raise NotImplementedError1324return self(ex.lhs() - ex.rhs())13251326def arithmetic(self, ex, operator):1327r"""1328EXAMPLES::13291330sage: from sage.ext.fast_callable import ExpressionTreeBuilder1331sage: etb = ExpressionTreeBuilder(vars=['x','y'])1332sage: var('x,y')1333(x, y)1334sage: (x+y)._fast_callable_(etb)1335add(v_0, v_1)1336sage: (-x)._fast_callable_(etb)1337neg(v_0)1338sage: (x+y+x^2)._fast_callable_(etb)1339add(add(ipow(v_0, 2), v_0), v_1)13401341TESTS:13421343Check if rational functions with numerator 1 can be converted. #8056::13441345sage: (1/pi/x)._fast_callable_(etb)1346div(1, mul(pi, v_0))13471348sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)1349sage: (x^7)._fast_callable_(etb)1350ipow(v_0, 7)1351sage: f(x)=1/pi/x; plot(f,2,3)1352"""1353# This used to convert the operands first. Doing it this way1354# instead gives a chance to notice powers with an integer1355# exponent before the exponent gets (potentially) converted1356# to another type.1357operands = ex.operands()1358if operator is _operator.pow:1359exponent = operands[1]1360if exponent == -1:1361return self.etb.call(_operator.div, 1, operands[0])1362elif exponent == 0.5:1363from sage.functions.all import sqrt1364return self.etb.call(sqrt, operands[0])1365elif exponent == -0.5:1366from sage.functions.all import sqrt1367return self.etb.call(_operator.div, 1, self.etb.call(sqrt, operands[0]))1368elif operator is _operator.neg:1369return self.etb.call(operator, operands[0])1370return reduce(lambda x,y: self.etb.call(operator, x,y), operands)13711372def symbol(self, ex):1373r"""1374Given an ExpressionTreeBuilder, return an Expression representing1375this value.13761377EXAMPLES::13781379sage: from sage.ext.fast_callable import ExpressionTreeBuilder1380sage: etb = ExpressionTreeBuilder(vars=['x','y'])1381sage: x, y, z = var('x,y,z')1382sage: x._fast_callable_(etb)1383v_01384sage: y._fast_callable_(etb)1385v_11386sage: z._fast_callable_(etb)1387Traceback (most recent call last):1388...1389ValueError: Variable 'z' not found1390"""1391return self.etb.var(SR(ex))13921393def composition(self, ex, function):1394r"""1395Given an ExpressionTreeBuilder, return an Expression representing1396this value.13971398EXAMPLES::13991400sage: from sage.ext.fast_callable import ExpressionTreeBuilder1401sage: etb = ExpressionTreeBuilder(vars=['x','y'])1402sage: x,y = var('x,y')1403sage: sin(sqrt(x+y))._fast_callable_(etb)1404sin(sqrt(add(v_0, v_1)))1405sage: arctan2(x,y)._fast_callable_(etb)1406{arctan2}(v_0, v_1)1407"""1408return self.etb.call(function, *ex.operands())140914101411def fast_callable(ex, etb):1412"""1413Given an ExpressionTreeBuilder *etb*, return an Expression representing1414the symbolic expression *ex*.14151416EXAMPLES::14171418sage: from sage.ext.fast_callable import ExpressionTreeBuilder1419sage: etb = ExpressionTreeBuilder(vars=['x','y'])1420sage: x,y = var('x,y')1421sage: f = y+2*x^21422sage: f._fast_callable_(etb)1423add(mul(ipow(v_0, 2), 2), v_1)14241425sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))1426sage: f._fast_callable_(etb)1427div(add(add(mul(ipow(v_0, 3), 2), mul(v_0, 2)), -1), mul(add(v_0, 1), add(v_0, -2)))14281429"""1430return FastCallableConverter(ex, etb)()14311432class RingConverter(Converter):1433def __init__(self, R, subs_dict=None):1434"""1435A class to convert expressions to other rings.14361437EXAMPLES::14381439sage: from sage.symbolic.expression_conversions import RingConverter1440sage: R = RingConverter(RIF, subs_dict={x:2})1441sage: R.ring1442Real Interval Field with 53 bits of precision1443sage: R.subs_dict1444{x: 2}1445sage: R(pi+e)14465.85987448204884?1447sage: loads(dumps(R))1448<sage.symbolic.expression_conversions.RingConverter object at 0x...>1449"""1450self.subs_dict = {} if subs_dict is None else subs_dict1451self.ring = R14521453def symbol(self, ex):1454"""1455All symbols appearing in the expression must appear in *subs_dict*1456in order for the conversion to be successful.14571458EXAMPLES::14591460sage: from sage.symbolic.expression_conversions import RingConverter1461sage: R = RingConverter(RIF, subs_dict={x:2})1462sage: R(x+pi)14635.141592653589794?14641465sage: R = RingConverter(RIF)1466sage: R(x+pi)1467Traceback (most recent call last):1468...1469TypeError1470"""1471try:1472return self.ring(self.subs_dict[ex])1473except KeyError:1474raise TypeError14751476def pyobject(self, ex, obj):1477"""1478EXAMPLES::14791480sage: from sage.symbolic.expression_conversions import RingConverter1481sage: R = RingConverter(RIF)1482sage: R(SR(5/2))14832.5000000000000000?1484"""1485return self.ring(obj)14861487def arithmetic(self, ex, operator):1488"""1489EXAMPLES::14901491sage: from sage.symbolic.expression_conversions import RingConverter1492sage: P.<z> = ZZ[]1493sage: R = RingConverter(P, subs_dict={x:z})1494sage: a = 2*x^2 + x + 31495sage: R(a)14962*z^2 + z + 31497"""1498if operator not in [_operator.add, _operator.mul, _operator.pow]:1499raise TypeError15001501operands = ex.operands()1502if operator is _operator.pow:1503from sage.all import Integer, Rational1504base, expt = operands15051506if expt == Rational(((1,2))):1507from sage.functions.all import sqrt1508return sqrt(self(base))1509try:1510expt = Integer(expt)1511except TypeError:1512pass15131514base = self(base)1515return base ** expt1516else:1517return reduce(operator, map(self, operands))15181519def composition(self, ex, operator):1520"""1521EXAMPLES::15221523sage: from sage.symbolic.expression_conversions import RingConverter1524sage: R = RingConverter(RIF)1525sage: R(cos(2))1526-0.4161468365471424?1527"""1528res = operator(*map(self, ex.operands()))1529if res.parent() is not self.ring:1530raise TypeError1531else:1532return res15331534class SubstituteFunction(Converter):1535def __init__(self, ex, original, new):1536"""1537A class that walks the tree and replaces occurrences of a1538function with another.15391540EXAMPLES::15411542sage: from sage.symbolic.expression_conversions import SubstituteFunction1543sage: foo = function('foo'); bar = function('bar')1544sage: s = SubstituteFunction(foo(x), foo, bar)1545sage: s(1/foo(foo(x)) + foo(2))15461/bar(bar(x)) + bar(2)1547"""1548self.original = original1549self.new = new1550self.ex = ex15511552def symbol(self, ex):1553"""1554EXAMPLES::15551556sage: from sage.symbolic.expression_conversions import SubstituteFunction1557sage: foo = function('foo'); bar = function('bar')1558sage: s = SubstituteFunction(foo(x), foo, bar)1559sage: s.symbol(x)1560x1561"""1562return ex15631564def pyobject(self, ex, obj):1565"""1566EXAMPLES::15671568sage: from sage.symbolic.expression_conversions import SubstituteFunction1569sage: foo = function('foo'); bar = function('bar')1570sage: s = SubstituteFunction(foo(x), foo, bar)1571sage: f = SR(2)1572sage: s.pyobject(f, f.pyobject())157321574sage: _.parent()1575Symbolic Ring1576"""1577return ex15781579def relation(self, ex, operator):1580"""1581EXAMPLES::15821583sage: from sage.symbolic.expression_conversions import SubstituteFunction1584sage: foo = function('foo'); bar = function('bar')1585sage: s = SubstituteFunction(foo(x), foo, bar)1586sage: eq = foo(x) == x1587sage: s.relation(eq, eq.operator())1588bar(x) == x1589"""1590return operator(self(ex.lhs()), self(ex.rhs()))15911592def arithmetic(self, ex, operator):1593"""1594EXAMPLES::15951596sage: from sage.symbolic.expression_conversions import SubstituteFunction1597sage: foo = function('foo'); bar = function('bar')1598sage: s = SubstituteFunction(foo(x), foo, bar)1599sage: f = x*foo(x) + pi/foo(x)1600sage: s.arithmetic(f, f.operator())1601x*bar(x) + pi/bar(x)1602"""1603return reduce(operator, map(self, ex.operands()))16041605def composition(self, ex, operator):1606"""1607EXAMPLES::16081609sage: from sage.symbolic.expression_conversions import SubstituteFunction1610sage: foo = function('foo'); bar = function('bar')1611sage: s = SubstituteFunction(foo(x), foo, bar)1612sage: f = foo(x)1613sage: s.composition(f, f.operator())1614bar(x)1615sage: f = foo(foo(x))1616sage: s.composition(f, f.operator())1617bar(bar(x))1618sage: f = sin(foo(x))1619sage: s.composition(f, f.operator())1620sin(bar(x))1621sage: f = foo(sin(x))1622sage: s.composition(f, f.operator())1623bar(sin(x))1624"""1625if operator == self.original:1626return self.new(*map(self, ex.operands()))1627else:1628return operator(*map(self, ex.operands()))16291630def derivative(self, ex, operator):1631"""1632EXAMPLES::16331634sage: from sage.symbolic.expression_conversions import SubstituteFunction1635sage: foo = function('foo'); bar = function('bar')1636sage: s = SubstituteFunction(foo(x), foo, bar)1637sage: f = foo(x).diff(x)1638sage: s.derivative(f, f.operator())1639D[0](bar)(x)16401641TESTS:16421643We can substitute functions under a derivative operator,1644:trac:`12801`::16451646sage: f = function('f')1647sage: g = function('g')1648sage: f(g(x)).diff(x).substitute_function(g, sin)1649cos(x)*D[0](f)(sin(x))16501651"""1652if operator.function() == self.original:1653return operator.change_function(self.new)(*map(self,ex.operands()))1654else:1655return operator(*map(self, ex.operands()))165616571658