Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/symbolic/expression_conversions.py
4077 views
1
"""
2
Conversion of symbolic expressions to other types
3
4
This module provides routines for converting new symbolic expressions
5
to other types. Primarily, it provides a class :class:`Converter`
6
which will walk the expression tree and make calls to methods
7
overridden by subclasses.
8
"""
9
###############################################################################
10
# Sage: Open Source Mathematical Software
11
# Copyright (C) 2009 Mike Hansen <[email protected]>
12
#
13
# Distributed under the terms of the GNU General Public License (GPL),
14
# version 2 or any later version. The full text of the GPL is available at:
15
# http://www.gnu.org/licenses/
16
###############################################################################
17
18
import operator as _operator
19
from sage.symbolic.ring import SR,var
20
from sage.symbolic.pynac import I
21
from sage.functions.all import exp
22
from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator
23
from sage.rings.number_field.number_field_element_quadratic import NumberFieldElement_quadratic
24
GaussianField = I.pyobject().parent()
25
26
class FakeExpression(object):
27
r"""
28
Pynac represents `x/y` as `xy^{-1}`. Often, tree-walkers would prefer
29
to see divisions instead of multiplications and negative exponents.
30
To allow for this (since Pynac internally doesn't have division at all),
31
there is a possibility to pass use_fake_div=True; this will rewrite
32
an Expression into a mixture of Expression and FakeExpression nodes,
33
where the FakeExpression nodes are used to represent divisions.
34
These nodes are intended to act sufficiently like Expression nodes
35
that tree-walkers won't care about the difference.
36
"""
37
38
def __init__(self, operands, operator):
39
"""
40
EXAMPLES::
41
42
sage: from sage.symbolic.expression_conversions import FakeExpression
43
sage: import operator; x,y = var('x,y')
44
sage: FakeExpression([x, y], operator.div)
45
FakeExpression([x, y], <built-in function div>)
46
"""
47
self._operands = operands
48
self._operator = operator
49
50
def __repr__(self):
51
"""
52
EXAMPLES::
53
54
sage: from sage.symbolic.expression_conversions import FakeExpression
55
sage: import operator; x,y = var('x,y')
56
sage: FakeExpression([x, y], operator.div)
57
FakeExpression([x, y], <built-in function div>)
58
"""
59
return "FakeExpression(%r, %r)"%(self._operands, self._operator)
60
61
def pyobject(self):
62
"""
63
EXAMPLES::
64
65
sage: from sage.symbolic.expression_conversions import FakeExpression
66
sage: import operator; x,y = var('x,y')
67
sage: f = FakeExpression([x, y], operator.div)
68
sage: f.pyobject()
69
Traceback (most recent call last):
70
...
71
TypeError: self must be a numeric expression
72
"""
73
raise TypeError, 'self must be a numeric expression'
74
75
def operands(self):
76
"""
77
EXAMPLES::
78
79
sage: from sage.symbolic.expression_conversions import FakeExpression
80
sage: import operator; x,y = var('x,y')
81
sage: f = FakeExpression([x, y], operator.div)
82
sage: f.operands()
83
[x, y]
84
"""
85
return self._operands
86
87
def __getitem__(self, i):
88
"""
89
EXAMPLES::
90
91
sage: from sage.symbolic.expression_conversions import FakeExpression
92
sage: import operator; x,y = var('x,y')
93
sage: f = FakeExpression([x, y], operator.div)
94
sage: f[0]
95
x
96
"""
97
return self._operands[i]
98
99
def operator(self):
100
"""
101
EXAMPLES::
102
103
sage: from sage.symbolic.expression_conversions import FakeExpression
104
sage: import operator; x,y = var('x,y')
105
sage: f = FakeExpression([x, y], operator.div)
106
sage: f.operator()
107
<built-in function div>
108
"""
109
return self._operator
110
111
def _fast_callable_(self, etb):
112
"""
113
EXAMPLES::
114
115
sage: from sage.symbolic.expression_conversions import FakeExpression
116
sage: import operator; x,y = var('x,y')
117
sage: f = FakeExpression([x, y], operator.div)
118
sage: fast_callable(f, vars=['x','y']).op_list()
119
[('load_arg', 0), ('load_arg', 1), 'div', 'return']
120
"""
121
return fast_callable(self, etb)
122
123
def _fast_float_(self, *vars):
124
"""
125
EXAMPLES::
126
127
sage: from sage.symbolic.expression_conversions import FakeExpression
128
sage: import operator; x,y = var('x,y')
129
sage: f = FakeExpression([x, y], operator.div)
130
sage: fast_float(f, 'x', 'y').op_list()
131
[('load_arg', 0), ('load_arg', 1), 'div', 'return']
132
"""
133
return fast_float(self, *vars)
134
135
class Converter(object):
136
def __init__(self, use_fake_div=False):
137
"""
138
If use_fake_div is set to True, then the converter will try to
139
replace expressions whose operator is operator.mul with the
140
corresponding expression whose operator is operator.div.
141
142
EXAMPLES::
143
144
sage: from sage.symbolic.expression_conversions import Converter
145
sage: c = Converter(use_fake_div=True)
146
sage: c.use_fake_div
147
True
148
"""
149
self.use_fake_div = use_fake_div
150
151
def __call__(self, ex=None):
152
"""
153
.. note::
154
155
If this object does not have an attribute *ex*, then an argument
156
must be passed into :meth`__call__`::
157
158
EXAMPLES::
159
160
sage: from sage.symbolic.expression_conversions import Converter
161
sage: c = Converter(use_fake_div=True)
162
sage: c(SR(2))
163
Traceback (most recent call last):
164
...
165
NotImplementedError: pyobject
166
sage: c(x+2)
167
Traceback (most recent call last):
168
...
169
NotImplementedError: arithmetic
170
sage: c(x)
171
Traceback (most recent call last):
172
...
173
NotImplementedError: symbol
174
sage: c(x==2)
175
Traceback (most recent call last):
176
...
177
NotImplementedError: relation
178
sage: c(sin(x))
179
Traceback (most recent call last):
180
...
181
NotImplementedError: composition
182
sage: c(function('f', x).diff(x))
183
Traceback (most recent call last):
184
...
185
NotImplementedError: derivative
186
187
We can set a default value for the argument by setting
188
the ``ex`` attribute::
189
190
sage: c.ex = SR(2)
191
sage: c()
192
Traceback (most recent call last):
193
...
194
NotImplementedError: pyobject
195
"""
196
if ex is None:
197
ex = self.ex
198
199
try:
200
obj = ex.pyobject()
201
return self.pyobject(ex, obj)
202
except TypeError, err:
203
if 'self must be a numeric expression' not in err:
204
raise err
205
206
operator = ex.operator()
207
if operator is None:
208
return self.symbol(ex)
209
210
if operator in arithmetic_operators:
211
if getattr(self, 'use_fake_div', False) and operator is _operator.mul:
212
div = self.get_fake_div(ex)
213
return self.arithmetic(div, div.operator())
214
return self.arithmetic(ex, operator)
215
elif operator in relation_operators:
216
return self.relation(ex, operator)
217
elif isinstance(operator, FDerivativeOperator):
218
return self.derivative(ex, operator)
219
else:
220
return self.composition(ex, operator)
221
222
def get_fake_div(self, ex):
223
"""
224
EXAMPLES::
225
226
sage: from sage.symbolic.expression_conversions import Converter
227
sage: c = Converter(use_fake_div=True)
228
sage: c.get_fake_div(sin(x)/x)
229
FakeExpression([sin(x), x], <built-in function div>)
230
sage: c.get_fake_div(-1*sin(x))
231
FakeExpression([sin(x)], <built-in function neg>)
232
sage: c.get_fake_div(-x)
233
FakeExpression([x], <built-in function neg>)
234
sage: c.get_fake_div((2*x^3+2*x-1)/((x-2)*(x+1)))
235
FakeExpression([2*x^3 + 2*x - 1, FakeExpression([x - 2, x + 1], <built-in function mul>)], <built-in function div>)
236
237
Check if #8056 is fixed, i.e., if numerator is 1.::
238
239
sage: c.get_fake_div(1/pi/x)
240
FakeExpression([1, FakeExpression([pi, x], <built-in function mul>)], <built-in function div>)
241
"""
242
d = []
243
n = []
244
for arg in ex.operands():
245
ops = arg.operands()
246
try:
247
if arg.operator() is _operator.pow and repr(ops[1]) == '-1':
248
d.append(ops[0])
249
else:
250
n.append(arg)
251
except TypeError:
252
n.append(arg)
253
254
len_d = len(d)
255
if len_d == 0:
256
repr_n = map(repr, n)
257
if len(n) == 2 and "-1" in repr_n:
258
a = n[0] if repr_n[1] == "-1" else n[1]
259
return FakeExpression([a], _operator.neg)
260
else:
261
return ex
262
elif len_d == 1:
263
d = d[0]
264
else:
265
d = FakeExpression(d, _operator.mul)
266
267
if len(n) == 0:
268
return FakeExpression([SR.one_element(), d], _operator.div)
269
elif len(n) == 1:
270
n = n[0]
271
else:
272
n = FakeExpression(n, _operator.mul)
273
274
return FakeExpression([n,d], _operator.div)
275
276
def pyobject(self, ex, obj):
277
"""
278
The input to this method is the result of calling
279
:meth:`pyobject` on a symbolic expression.
280
281
.. note::
282
283
Note that if a constant such as ``pi`` is encountered in
284
the expression tree, its corresponding pyobject which is an
285
instance of :class:`sage.symbolic.constants.Pi` will be
286
passed into this method. One cannot do arithmetic using
287
such an object.
288
289
TESTS::
290
291
sage: from sage.symbolic.expression_conversions import Converter
292
sage: f = SR(1)
293
sage: Converter().pyobject(f, f.pyobject())
294
Traceback (most recent call last):
295
...
296
NotImplementedError: pyobject
297
"""
298
raise NotImplementedError, "pyobject"
299
300
def symbol(self, ex):
301
"""
302
The input to this method is a symbolic expression which
303
corresponds to a single variable. For example, this method
304
could be used to return a generator for a polynomial ring.
305
306
TESTS::
307
308
sage: from sage.symbolic.expression_conversions import Converter
309
sage: Converter().symbol(x)
310
Traceback (most recent call last):
311
...
312
NotImplementedError: symbol
313
"""
314
raise NotImplementedError, "symbol"
315
316
def relation(self, ex, operator):
317
"""
318
The input to this method is a symbolic expression which
319
corresponds to a relation.
320
321
TESTS::
322
323
sage: from sage.symbolic.expression_conversions import Converter
324
sage: import operator
325
sage: Converter().relation(x==3, operator.eq)
326
Traceback (most recent call last):
327
...
328
NotImplementedError: relation
329
sage: Converter().relation(x==3, operator.lt)
330
Traceback (most recent call last):
331
...
332
NotImplementedError: relation
333
"""
334
raise NotImplementedError, "relation"
335
336
def derivative(self, ex, operator):
337
"""
338
The input to this method is a symbolic expression which
339
corresponds to a relation.
340
341
TESTS::
342
343
sage: from sage.symbolic.expression_conversions import Converter
344
sage: a = function('f', x).diff(x); a
345
D[0](f)(x)
346
sage: Converter().derivative(a, a.operator())
347
Traceback (most recent call last):
348
...
349
NotImplementedError: derivative
350
"""
351
raise NotImplementedError, "derivative"
352
353
def arithmetic(self, ex, operator):
354
"""
355
The input to this method is a symbolic expression and the
356
infix operator corresponding to that expression. Typically,
357
one will convert all of the arguments and then perform the
358
operation afterward.
359
360
TESTS::
361
362
sage: from sage.symbolic.expression_conversions import Converter
363
sage: f = x + 2
364
sage: Converter().arithmetic(f, f.operator())
365
Traceback (most recent call last):
366
...
367
NotImplementedError: arithmetic
368
"""
369
raise NotImplementedError, "arithmetic"
370
371
def composition(self, ex, operator):
372
"""
373
The input to this method is a symbolic expression and its
374
operator. This method will get called when you have a symbolic
375
function application.
376
377
TESTS::
378
379
sage: from sage.symbolic.expression_conversions import Converter
380
sage: f = sin(2)
381
sage: Converter().composition(f, f.operator())
382
Traceback (most recent call last):
383
...
384
NotImplementedError: composition
385
"""
386
raise NotImplementedError, "composition"
387
388
class InterfaceInit(Converter):
389
def __init__(self, interface):
390
"""
391
EXAMPLES::
392
393
sage: from sage.symbolic.expression_conversions import InterfaceInit
394
sage: m = InterfaceInit(maxima)
395
sage: a = pi + 2
396
sage: m(a)
397
'(%pi)+(2)'
398
sage: m(sin(a))
399
'sin((%pi)+(2))'
400
sage: m(exp(x^2) + pi + 2)
401
'(%pi)+(exp((x)^(2)))+(2)'
402
403
"""
404
self.name_init = "_%s_init_"%interface.name()
405
self.interface = interface
406
self.relation_symbols = interface._relation_symbols()
407
408
def symbol(self, ex):
409
"""
410
EXAMPLES::
411
412
sage: from sage.symbolic.expression_conversions import InterfaceInit
413
sage: m = InterfaceInit(maxima)
414
sage: m.symbol(x)
415
'x'
416
sage: f(x) = x
417
sage: m.symbol(f)
418
'x'
419
"""
420
return repr(SR(ex))
421
422
def pyobject(self, ex, obj):
423
"""
424
EXAMPLES::
425
426
sage: from sage.symbolic.expression_conversions import InterfaceInit
427
sage: ii = InterfaceInit(gp)
428
sage: f = 2+I
429
sage: ii.pyobject(f, f.pyobject())
430
'I + 2'
431
432
sage: ii.pyobject(SR(2), 2)
433
'2'
434
435
sage: ii.pyobject(pi, pi.pyobject())
436
'Pi'
437
"""
438
if (self.interface.name() in ['pari','gp'] and
439
isinstance(obj, NumberFieldElement_quadratic) and
440
obj.parent() == GaussianField):
441
return repr(obj)
442
try:
443
return getattr(obj, self.name_init)()
444
except AttributeError:
445
return repr(obj)
446
447
def relation(self, ex, operator):
448
"""
449
EXAMPLES::
450
451
sage: import operator
452
sage: from sage.symbolic.expression_conversions import InterfaceInit
453
sage: m = InterfaceInit(maxima)
454
sage: m.relation(x==3, operator.eq)
455
'x = 3'
456
sage: m.relation(x==3, operator.lt)
457
'x < 3'
458
"""
459
return "%s %s %s"%(self(ex.lhs()), self.relation_symbols[operator],
460
self(ex.rhs()))
461
462
def derivative(self, ex, operator):
463
"""
464
EXAMPLES::
465
466
sage: from sage.symbolic.expression_conversions import InterfaceInit
467
sage: m = InterfaceInit(maxima)
468
sage: f = function('f')
469
sage: a = f(x).diff(x); a
470
D[0](f)(x)
471
sage: print m.derivative(a, a.operator())
472
diff('f(x), x, 1)
473
sage: b = f(x).diff(x, x)
474
sage: print m.derivative(b, b.operator())
475
diff('f(x), x, 2)
476
477
We can also convert expressions where the argument is not just a
478
variable, but the result is an "at" expression using temporary
479
variables::
480
481
sage: y = var('y')
482
sage: t = (f(x*y).diff(x))/y
483
sage: t
484
D[0](f)(x*y)
485
sage: m.derivative(t, t.operator())
486
"at(diff('f(t0), t0, 1), [t0 = x*y])"
487
"""
488
#This code should probably be moved into the interface
489
#object in a nice way.
490
from sage.symbolic.ring import is_SymbolicVariable
491
if self.name_init != "_maxima_init_":
492
raise NotImplementedError
493
args = ex.operands()
494
if (not all(is_SymbolicVariable(v) for v in args) or
495
len(args) != len(set(args))):
496
# An evaluated derivative of the form f'(1) is not a
497
# symbolic variable, yet we would like to treat it like
498
# one. So, we replace the argument `1` with a temporary
499
# variable e.g. `t0` and then evaluate the derivative
500
# f'(t0) symbolically at t0=1. See trac #12796.
501
temp_args=[var("t%s"%i) for i in range(len(args))]
502
f = operator.function()
503
params = operator.parameter_set()
504
params = ["%s, %s"%(temp_args[i], params.count(i)) for i in set(params)]
505
subs = ["%s = %s"%(t,a) for t,a in zip(temp_args,args)]
506
return "at(diff('%s(%s), %s), [%s])"%(f.name(),
507
", ".join(map(repr,temp_args)),
508
", ".join(params),
509
", ".join(subs))
510
511
f = operator.function()
512
params = operator.parameter_set()
513
params = ["%s, %s"%(args[i], params.count(i)) for i in set(params)]
514
515
return "diff('%s(%s), %s)"%(f.name(),
516
", ".join(map(repr, args)),
517
", ".join(params))
518
519
def arithmetic(self, ex, operator):
520
"""
521
EXAMPLES::
522
523
sage: import operator
524
sage: from sage.symbolic.expression_conversions import InterfaceInit
525
sage: m = InterfaceInit(maxima)
526
sage: m.arithmetic(x+2, operator.add)
527
'(x)+(2)'
528
"""
529
args = ["(%s)"%self(op) for op in ex.operands()]
530
return arithmetic_operators[operator].join(args)
531
532
def composition(self, ex, operator):
533
"""
534
EXAMPLES::
535
536
sage: from sage.symbolic.expression_conversions import InterfaceInit
537
sage: m = InterfaceInit(maxima)
538
sage: m.composition(sin(x), sin)
539
'sin(x)'
540
sage: m.composition(ceil(x), ceil)
541
'ceiling(x)'
542
543
sage: m = InterfaceInit(mathematica)
544
sage: m.composition(sin(x), sin)
545
'Sin[x]'
546
"""
547
ops = ex.operands()
548
#FIXME: consider stripping pyobjects() in ops
549
if hasattr(operator, self.name_init + "evaled_"):
550
return getattr(operator, self.name_init + "evaled_")(*ops)
551
else:
552
ops = map(self, ops)
553
try:
554
op = getattr(operator, self.name_init)()
555
except (TypeError, AttributeError):
556
op = repr(operator)
557
558
return self.interface._function_call_string(op,ops,[])
559
560
#########
561
# Sympy #
562
#########
563
class SympyConverter(Converter):
564
"""
565
Converts any expression to SymPy.
566
567
EXAMPLE::
568
569
sage: import sympy
570
sage: var('x,y')
571
(x, y)
572
sage: f = exp(x^2) - arcsin(pi+x)/y
573
sage: f._sympy_()
574
exp(x**2) - asin(x + pi)/y
575
sage: _._sage_()
576
-arcsin(pi + x)/y + e^(x^2)
577
578
sage: sympy.sympify(x) # indirect doctest
579
x
580
581
TESTS:
582
583
Make sure we can convert I (trac #6424)::
584
585
sage: bool(I._sympy_() == I)
586
True
587
sage: (x+I)._sympy_()
588
x + I
589
590
"""
591
def pyobject(self, ex, obj):
592
"""
593
EXAMPLES::
594
595
sage: from sage.symbolic.expression_conversions import SympyConverter
596
sage: s = SympyConverter()
597
sage: f = SR(2)
598
sage: s.pyobject(f, f.pyobject())
599
2
600
sage: type(_)
601
<class 'sympy.core.numbers.Integer'>
602
"""
603
try:
604
return obj._sympy_()
605
except AttributeError:
606
return obj
607
608
def arithmetic(self, ex, operator):
609
"""
610
EXAMPLES::
611
612
sage: from sage.symbolic.expression_conversions import SympyConverter
613
sage: s = SympyConverter()
614
sage: f = x + 2
615
sage: s.arithmetic(f, f.operator())
616
x + 2
617
"""
618
import sympy
619
operator = arithmetic_operators[operator]
620
ops = [sympy.sympify(self(a)) for a in ex.operands()]
621
if operator == "+":
622
return sympy.Add(*ops)
623
elif operator == "*":
624
return sympy.Mul(*ops)
625
elif operator == "-":
626
return sympy.Sub(*ops)
627
elif operator == "/":
628
return sympy.Div(*ops)
629
elif operator == "^":
630
return sympy.Pow(*ops)
631
else:
632
raise NotImplementedError
633
634
def symbol(self, ex):
635
"""
636
EXAMPLES::
637
638
sage: from sage.symbolic.expression_conversions import SympyConverter
639
sage: s = SympyConverter()
640
sage: s.symbol(x)
641
x
642
sage: type(_)
643
<class 'sympy.core.symbol.Symbol'>
644
"""
645
import sympy
646
return sympy.symbols(repr(ex))
647
648
def composition(self, ex, operator):
649
"""
650
EXAMPLES::
651
652
sage: from sage.symbolic.expression_conversions import SympyConverter
653
sage: s = SympyConverter()
654
sage: f = sin(2)
655
sage: s.composition(f, f.operator())
656
sin(2)
657
sage: type(_)
658
sin
659
sage: f = arcsin(2)
660
sage: s.composition(f, f.operator())
661
asin(2)
662
"""
663
f = operator._sympy_init_()
664
g = ex.operands()
665
import sympy
666
667
f_sympy = getattr(sympy, f, None)
668
if f_sympy:
669
return f_sympy(*sympy.sympify(g))
670
else:
671
raise NotImplementedError("SymPy function '%s' doesn't exist" % f)
672
673
sympy = SympyConverter()
674
675
#############
676
# Algebraic #
677
#############
678
class AlgebraicConverter(Converter):
679
def __init__(self, field):
680
"""
681
EXAMPLES::
682
683
sage: from sage.symbolic.expression_conversions import AlgebraicConverter
684
sage: a = AlgebraicConverter(QQbar)
685
sage: a.field
686
Algebraic Field
687
sage: a.reciprocal_trig_functions['cot']
688
tan
689
"""
690
self.field = field
691
692
from sage.functions.all import reciprocal_trig_functions
693
self.reciprocal_trig_functions = reciprocal_trig_functions
694
695
def pyobject(self, ex, obj):
696
"""
697
EXAMPLES::
698
699
sage: from sage.symbolic.expression_conversions import AlgebraicConverter
700
sage: a = AlgebraicConverter(QQbar)
701
sage: f = SR(2)
702
sage: a.pyobject(f, f.pyobject())
703
2
704
sage: _.parent()
705
Algebraic Field
706
"""
707
return self.field(obj)
708
709
def arithmetic(self, ex, operator):
710
"""
711
Convert a symbolic expression to an algebraic number.
712
713
EXAMPLES::
714
715
sage: from sage.symbolic.expression_conversions import AlgebraicConverter
716
sage: f = 2^(1/2)
717
sage: a = AlgebraicConverter(QQbar)
718
sage: a.arithmetic(f, f.operator())
719
1.414213562373095?
720
721
TESTS::
722
723
sage: f = pi^6
724
sage: a = AlgebraicConverter(QQbar)
725
sage: a.arithmetic(f, f.operator())
726
Traceback (most recent call last):
727
...
728
TypeError: unable to convert pi^6 to Algebraic Field
729
"""
730
# We try to avoid simplifying, because maxima's simplify command
731
# can change the value of a radical expression (by changing which
732
# root is selected).
733
try:
734
if operator is _operator.pow:
735
from sage.rings.all import Rational
736
base, expt = ex.operands()
737
base = self.field(base)
738
expt = Rational(expt)
739
return self.field(base**expt)
740
else:
741
return reduce(operator, map(self, ex.operands()))
742
except TypeError:
743
pass
744
745
if operator is _operator.pow:
746
from sage.symbolic.constants import e, pi, I
747
base, expt = ex.operands()
748
if base == e and expt / (pi*I) in QQ:
749
return exp(expt)._algebraic_(self.field)
750
751
raise TypeError, "unable to convert %s to %s"%(ex, self.field)
752
753
def composition(self, ex, operator):
754
"""
755
Coerce to an algebraic number.
756
757
EXAMPLES::
758
759
sage: from sage.symbolic.expression_conversions import AlgebraicConverter
760
sage: a = AlgebraicConverter(QQbar)
761
sage: a.composition(exp(I*pi/3), exp)
762
0.500000000000000? + 0.866025403784439?*I
763
sage: a.composition(sin(pi/5), sin)
764
0.5877852522924731? + 0.?e-18*I
765
766
TESTS::
767
768
sage: QQbar(zeta(7))
769
Traceback (most recent call last):
770
...
771
TypeError: unable to convert zeta(7) to Algebraic Field
772
"""
773
func = operator
774
operand, = ex.operands()
775
776
QQbar = self.field.algebraic_closure()
777
# Note that comparing functions themselves goes via maxima, and is SLOW
778
func_name = repr(func)
779
if func_name == 'exp':
780
rat_arg = (operand.imag()/(2*ex.parent().pi()))._rational_()
781
if rat_arg == 0:
782
# here we will either try and simplify, or return
783
raise ValueError, "Unable to represent as an algebraic number."
784
real = operand.real()
785
if real:
786
mag = exp(operand.real())._algebraic_(QQbar)
787
else:
788
mag = 1
789
res = mag * QQbar.zeta(rat_arg.denom())**rat_arg.numer()
790
elif func_name in ['sin', 'cos', 'tan']:
791
exp_ia = exp(SR(-1).sqrt()*operand)._algebraic_(QQbar)
792
if func_name == 'sin':
793
res = (exp_ia - ~exp_ia)/(2*QQbar.zeta(4))
794
elif func_name == 'cos':
795
res = (exp_ia + ~exp_ia)/2
796
else:
797
res = -QQbar.zeta(4)*(exp_ia - ~exp_ia)/(exp_ia + ~exp_ia)
798
elif func_name in ['sinh', 'cosh', 'tanh']:
799
exp_a = exp(operand)._algebraic_(QQbar)
800
if func_name == 'sinh':
801
res = (exp_a - ~exp_a)/2
802
elif func_name == 'cosh':
803
res = (exp_a + ~exp_a)/2
804
else:
805
res = (exp_a - ~exp_a) / (exp_a + ~exp_a)
806
elif func_name in self.reciprocal_trig_functions:
807
res = ~self.reciprocal_trig_functions[func_name](operand)._algebraic_(QQbar)
808
else:
809
res = func(operand._algebraic_(self.field))
810
#We have to handle the case where we get the same symbolic
811
#expression back. For example, QQbar(zeta(7)). See
812
#ticket #12665.
813
if cmp(res, ex) == 0:
814
raise TypeError, "unable to convert %s to %s"%(ex, self.field)
815
return self.field(res)
816
817
def algebraic(ex, field):
818
"""
819
Returns the symbolic expression *ex* as a element of the algebraic
820
field *field*.
821
822
EXAMPLES::
823
824
sage: a = SR(5/6)
825
sage: AA(a)
826
5/6
827
sage: type(AA(a))
828
<class 'sage.rings.qqbar.AlgebraicReal'>
829
sage: QQbar(a)
830
5/6
831
sage: type(QQbar(a))
832
<class 'sage.rings.qqbar.AlgebraicNumber'>
833
sage: QQbar(i)
834
1*I
835
sage: AA(golden_ratio)
836
1.618033988749895?
837
sage: QQbar(golden_ratio)
838
1.618033988749895?
839
sage: QQbar(sin(pi/3))
840
0.866025403784439?
841
842
sage: QQbar(sqrt(2) + sqrt(8))
843
4.242640687119285?
844
sage: AA(sqrt(2) ^ 4) == 4
845
True
846
sage: AA(-golden_ratio)
847
-1.618033988749895?
848
sage: QQbar((2*I)^(1/2))
849
1 + 1*I
850
sage: QQbar(e^(pi*I/3))
851
0.500000000000000? + 0.866025403784439?*I
852
853
sage: AA(x*sin(0))
854
0
855
sage: QQbar(x*sin(0))
856
0
857
"""
858
return AlgebraicConverter(field)(ex)
859
860
##############
861
# Polynomial #
862
##############
863
class PolynomialConverter(Converter):
864
def __init__(self, ex, base_ring=None, ring=None):
865
"""
866
EXAMPLES::
867
868
sage: from sage.symbolic.expression_conversions import PolynomialConverter
869
sage: x, y = var('x,y')
870
sage: p = PolynomialConverter(x+y, base_ring=QQ)
871
sage: p.base_ring
872
Rational Field
873
sage: p.ring
874
Multivariate Polynomial Ring in x, y over Rational Field
875
876
sage: p = PolynomialConverter(x, base_ring=QQ)
877
sage: p.base_ring
878
Rational Field
879
sage: p.ring
880
Univariate Polynomial Ring in x over Rational Field
881
882
sage: p = PolynomialConverter(x, ring=QQ['x,y'])
883
sage: p.base_ring
884
Rational Field
885
sage: p.ring
886
Multivariate Polynomial Ring in x, y over Rational Field
887
888
sage: p = PolynomialConverter(x+y, ring=QQ['x'])
889
Traceback (most recent call last):
890
...
891
TypeError: y is not a variable of Univariate Polynomial Ring in x over Rational Field
892
893
894
"""
895
if not (ring is None or base_ring is None):
896
raise TypeError, "either base_ring or ring must be specified, but not both"
897
self.ex = ex
898
899
if ring is not None:
900
base_ring = ring.base_ring()
901
G = ring.variable_names_recursive()
902
for v in ex.variables():
903
if repr(v) not in G and v not in base_ring:
904
raise TypeError, "%s is not a variable of %s" %(v, ring)
905
self.ring = ring
906
self.base_ring = base_ring
907
elif base_ring is not None:
908
self.base_ring = base_ring
909
vars = self.ex.variables()
910
if len(vars) == 0:
911
vars = ['x']
912
from sage.rings.all import PolynomialRing
913
self.ring = PolynomialRing(self.base_ring, names=vars)
914
else:
915
raise TypeError, "either a ring or base ring must be specified"
916
917
def symbol(self, ex):
918
"""
919
Returns a variable in the polynomial ring.
920
921
EXAMPLES::
922
923
sage: from sage.symbolic.expression_conversions import PolynomialConverter
924
sage: p = PolynomialConverter(x, base_ring=QQ)
925
sage: p.symbol(x)
926
x
927
sage: _.parent()
928
Univariate Polynomial Ring in x over Rational Field
929
"""
930
return self.ring(repr(ex))
931
932
def pyobject(self, ex, obj):
933
"""
934
EXAMPLES::
935
936
sage: from sage.symbolic.expression_conversions import PolynomialConverter
937
sage: p = PolynomialConverter(x, base_ring=QQ)
938
sage: f = SR(2)
939
sage: p.pyobject(f, f.pyobject())
940
2
941
sage: _.parent()
942
Rational Field
943
"""
944
return self.base_ring(obj)
945
946
def composition(self, ex, operator):
947
"""
948
EXAMPLES::
949
950
sage: from sage.symbolic.expression_conversions import PolynomialConverter
951
sage: a = sin(2)
952
sage: p = PolynomialConverter(a*x, base_ring=RR)
953
sage: p.composition(a, a.operator())
954
0.909297426825682
955
"""
956
return self.base_ring(ex)
957
958
def relation(self, ex, op):
959
"""
960
EXAMPLES::
961
962
sage: import operator
963
sage: from sage.symbolic.expression_conversions import PolynomialConverter
964
965
sage: x, y = var('x, y')
966
sage: p = PolynomialConverter(x, base_ring=RR)
967
968
sage: p.relation(x==3, operator.eq)
969
x - 3.00000000000000
970
sage: p.relation(x==3, operator.lt)
971
Traceback (most recent call last):
972
...
973
ValueError: Unable to represent as a polynomial
974
975
sage: p = PolynomialConverter(x - y, base_ring=QQ)
976
sage: p.relation(x^2 - y^3 + 1 == x^3, operator.eq)
977
-x^3 - y^3 + x^2 + 1
978
"""
979
import operator
980
if op == operator.eq:
981
return self(ex.lhs()) - self(ex.rhs())
982
else:
983
raise ValueError, "Unable to represent as a polynomial"
984
985
def arithmetic(self, ex, operator):
986
"""
987
EXAMPLES::
988
989
sage: import operator
990
sage: from sage.symbolic.expression_conversions import PolynomialConverter
991
992
sage: x, y = var('x, y')
993
sage: p = PolynomialConverter(x, base_ring=RR)
994
sage: p.arithmetic(pi+e, operator.add)
995
5.85987448204884
996
sage: p.arithmetic(x^2, operator.pow)
997
x^2
998
999
sage: p = PolynomialConverter(x+y, base_ring=RR)
1000
sage: p.arithmetic(x*y+y^2, operator.add)
1001
x*y + y^2
1002
"""
1003
if len(ex.variables()) == 0:
1004
return self.base_ring(ex)
1005
elif operator == _operator.pow:
1006
from sage.rings.all import Integer
1007
base, exp = ex.operands()
1008
return self(base)**Integer(exp)
1009
else:
1010
ops = [self(a) for a in ex.operands()]
1011
return reduce(operator, ops)
1012
1013
def polynomial(ex, base_ring=None, ring=None):
1014
"""
1015
Returns a polynomial from the symbolic expression *ex*. Either a
1016
base ring *base_ring* or a polynomial ring *ring* can be specified
1017
for the parent of result. If just a base ring is given, then the variables
1018
of the base ring will be the variables of the expression *ex*.
1019
1020
EXAMPLES::
1021
1022
sage: from sage.symbolic.expression_conversions import polynomial
1023
sage: f = x^2 + 2
1024
sage: polynomial(f, base_ring=QQ)
1025
x^2 + 2
1026
sage: _.parent()
1027
Univariate Polynomial Ring in x over Rational Field
1028
1029
sage: polynomial(f, ring=QQ['x,y'])
1030
x^2 + 2
1031
sage: _.parent()
1032
Multivariate Polynomial Ring in x, y over Rational Field
1033
1034
sage: x, y = var('x, y')
1035
sage: polynomial(x + y^2, ring=QQ['x,y'])
1036
y^2 + x
1037
sage: _.parent()
1038
Multivariate Polynomial Ring in x, y over Rational Field
1039
1040
sage: s,t=var('s,t')
1041
sage: expr=t^2-2*s*t+1
1042
sage: expr.polynomial(None,ring=SR['t'])
1043
t^2 - 2*s*t + 1
1044
sage: _.parent()
1045
Univariate Polynomial Ring in t over Symbolic Ring
1046
1047
1048
1049
The polynomials can have arbitrary (constant) coefficients so long as
1050
they coerce into the base ring::
1051
1052
sage: polynomial(2^sin(2)*x^2 + exp(3), base_ring=RR)
1053
1.87813065119873*x^2 + 20.0855369231877
1054
"""
1055
converter = PolynomialConverter(ex, base_ring=base_ring, ring=ring)
1056
res = converter()
1057
return converter.ring(res)
1058
1059
##############
1060
# Fast Float #
1061
##############
1062
1063
class FastFloatConverter(Converter):
1064
def __init__(self, ex, *vars):
1065
"""
1066
Returns an object which provides fast floating point
1067
evaluation of the symbolic expression *ex*. This is an class
1068
used internally and is not meant to be used directly.
1069
1070
See :mod:`sage.ext.fast_eval` for more information.
1071
1072
EXAMPLES::
1073
1074
sage: x,y,z = var('x,y,z')
1075
sage: f = 1 + sin(x)/x + sqrt(z^2+y^2)/cosh(x)
1076
sage: ff = f._fast_float_('x', 'y', 'z')
1077
sage: f(x=1.0,y=2.0,z=3.0).n()
1078
4.1780638977...
1079
sage: ff(1.0,2.0,3.0)
1080
4.1780638977...
1081
1082
Using _fast_float_ without specifying the variable names is
1083
deprecated::
1084
1085
sage: f = x._fast_float_()
1086
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=...)
1087
sage: f(1.2)
1088
1.2
1089
1090
Using _fast_float_ on a function which is the identity is
1091
now supported (see Trac 10246)::
1092
1093
sage: f = symbolic_expression(x).function(x)
1094
sage: f._fast_float_(x)
1095
<sage.ext.fast_eval.FastDoubleFunc object at ...>
1096
sage: f(22)
1097
22
1098
"""
1099
self.ex = ex
1100
1101
if vars == ():
1102
try:
1103
vars = ex.arguments()
1104
except AttributeError:
1105
vars = ex.variables()
1106
1107
if vars:
1108
from sage.misc.misc import deprecation
1109
deprecation("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=...)")
1110
1111
1112
self.vars = vars
1113
1114
import sage.ext.fast_eval as fast_float
1115
self.ff = fast_float
1116
1117
Converter.__init__(self, use_fake_div=True)
1118
1119
def relation(self, ex, operator):
1120
"""
1121
EXAMPLES::
1122
1123
sage: ff = fast_float(x == 2, 'x')
1124
sage: ff(2)
1125
0.0
1126
sage: ff(4)
1127
2.0
1128
sage: ff = fast_float(x < 2, 'x')
1129
Traceback (most recent call last):
1130
...
1131
NotImplementedError
1132
"""
1133
if operator is not _operator.eq:
1134
raise NotImplementedError
1135
return self(ex.lhs() - ex.rhs())
1136
1137
def pyobject(self, ex, obj):
1138
"""
1139
EXAMPLES::
1140
1141
sage: f = SR(2)._fast_float_()
1142
sage: f(3)
1143
2.0
1144
"""
1145
try:
1146
return obj._fast_float_(*self.vars)
1147
except AttributeError:
1148
return self.ff.fast_float_constant(float(obj))
1149
1150
def symbol(self, ex):
1151
r"""
1152
EXAMPLES::
1153
1154
sage: f = x._fast_float_('x', 'y')
1155
sage: f(1,2)
1156
1.0
1157
sage: f = x._fast_float_('y', 'x')
1158
sage: f(1,2)
1159
2.0
1160
"""
1161
if self.vars == ():
1162
return self.ff.fast_float_arg(0)
1163
1164
vars = list(self.vars)
1165
name = repr(ex)
1166
if name in vars:
1167
return self.ff.fast_float_arg(vars.index(name))
1168
svars = [repr(x) for x in vars]
1169
if name in svars:
1170
return self.ff.fast_float_arg(svars.index(name))
1171
1172
if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x
1173
name = repr(SR(ex)) # this gets back just the 'output' of the function
1174
if name in svars:
1175
return self.ff.fast_float_arg(svars.index(name))
1176
1177
try:
1178
return self.ff.fast_float_constant(float(ex))
1179
except TypeError:
1180
raise ValueError, "free variable: %s" % repr(ex)
1181
1182
def arithmetic(self, ex, operator):
1183
"""
1184
EXAMPLES::
1185
1186
sage: x,y = var('x,y')
1187
sage: f = x*x-y
1188
sage: ff = f._fast_float_('x','y')
1189
sage: ff(2,3)
1190
1.0
1191
1192
sage: a = x + 2*y
1193
sage: f = a._fast_float_('x', 'y')
1194
sage: f(1,0)
1195
1.0
1196
sage: f(0,1)
1197
2.0
1198
1199
sage: f = sqrt(x)._fast_float_('x'); f.op_list()
1200
['load 0', 'call sqrt(1)']
1201
1202
sage: f = (1/2*x)._fast_float_('x'); f.op_list()
1203
['load 0', 'push 0.5', 'mul']
1204
"""
1205
operands = ex.operands()
1206
if operator is _operator.neg:
1207
return operator(self(operands[0]))
1208
1209
from sage.rings.all import Rational
1210
if operator is _operator.pow and operands[1] == Rational(((1,2))):
1211
from sage.functions.all import sqrt
1212
return sqrt(self(operands[0]))
1213
fops = map(self, operands)
1214
return reduce(operator, fops)
1215
1216
def composition(self, ex, operator):
1217
"""
1218
EXAMPLES::
1219
1220
sage: f = sqrt(x)._fast_float_('x')
1221
sage: f(2)
1222
1.41421356237309...
1223
sage: y = var('y')
1224
sage: f = sqrt(x+y)._fast_float_('x', 'y')
1225
sage: f(1,1)
1226
1.41421356237309...
1227
1228
::
1229
1230
sage: f = sqrt(x+2*y)._fast_float_('x', 'y')
1231
sage: f(2,0)
1232
1.41421356237309...
1233
sage: f(0,1)
1234
1.41421356237309...
1235
"""
1236
f = operator
1237
g = map(self, ex.operands())
1238
try:
1239
return f(*g)
1240
except TypeError:
1241
from sage.functions.other import abs_symbolic
1242
if f is abs_symbolic:
1243
return abs(*g) # special case
1244
else:
1245
return self.ff.fast_float_func(f, *g)
1246
1247
def fast_float(ex, *vars):
1248
"""
1249
Returns an object which provides fast floating point evaluation of
1250
the symbolic expression *ex*.
1251
1252
See :mod:`sage.ext.fast_eval` for more information.
1253
1254
EXAMPLES::
1255
1256
sage: from sage.symbolic.expression_conversions import fast_float
1257
sage: f = sqrt(x+1)
1258
sage: ff = fast_float(f, 'x')
1259
sage: ff(1.0)
1260
1.4142135623730951
1261
"""
1262
return FastFloatConverter(ex, *vars)()
1263
1264
#################
1265
# Fast Callable #
1266
#################
1267
1268
class FastCallableConverter(Converter):
1269
def __init__(self, ex, etb):
1270
"""
1271
EXAMPLES::
1272
1273
sage: from sage.symbolic.expression_conversions import FastCallableConverter
1274
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1275
sage: etb = ExpressionTreeBuilder(vars=['x'])
1276
sage: f = FastCallableConverter(x+2, etb)
1277
sage: f.ex
1278
x + 2
1279
sage: f.etb
1280
<sage.ext.fast_callable.ExpressionTreeBuilder object at 0x...>
1281
sage: f.use_fake_div
1282
True
1283
"""
1284
self.ex = ex
1285
self.etb = etb
1286
Converter.__init__(self, use_fake_div=True)
1287
1288
def pyobject(self, ex, obj):
1289
r"""
1290
EXAMPLES::
1291
1292
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1293
sage: etb = ExpressionTreeBuilder(vars=['x'])
1294
sage: pi._fast_callable_(etb)
1295
pi
1296
sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1297
sage: pi._fast_callable_(etb)
1298
3.14159265359
1299
"""
1300
from sage.symbolic.constants import Constant
1301
if isinstance(obj, Constant):
1302
obj = obj.expression()
1303
return self.etb.constant(obj)
1304
1305
def relation(self, ex, operator):
1306
"""
1307
EXAMPLES::
1308
1309
sage: ff = fast_callable(x == 2, vars=['x'])
1310
sage: ff(2)
1311
0
1312
sage: ff(4)
1313
2
1314
sage: ff = fast_callable(x < 2, vars=['x'])
1315
Traceback (most recent call last):
1316
...
1317
NotImplementedError
1318
"""
1319
if operator is not _operator.eq:
1320
raise NotImplementedError
1321
return self(ex.lhs() - ex.rhs())
1322
1323
def arithmetic(self, ex, operator):
1324
r"""
1325
EXAMPLES::
1326
1327
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1328
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1329
sage: var('x,y')
1330
(x, y)
1331
sage: (x+y)._fast_callable_(etb)
1332
add(v_0, v_1)
1333
sage: (-x)._fast_callable_(etb)
1334
neg(v_0)
1335
sage: (x+y+x^2)._fast_callable_(etb)
1336
add(add(ipow(v_0, 2), v_0), v_1)
1337
1338
TESTS:
1339
1340
Check if rational functions with numerator 1 can be converted. #8056::
1341
1342
sage: (1/pi/x)._fast_callable_(etb)
1343
div(1, mul(pi, v_0))
1344
1345
sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1346
sage: (x^7)._fast_callable_(etb)
1347
ipow(v_0, 7)
1348
sage: f(x)=1/pi/x; plot(f,2,3)
1349
"""
1350
# This used to convert the operands first. Doing it this way
1351
# instead gives a chance to notice powers with an integer
1352
# exponent before the exponent gets (potentially) converted
1353
# to another type.
1354
operands = ex.operands()
1355
if operator is _operator.pow:
1356
exponent = operands[1]
1357
if exponent == -1:
1358
return self.etb.call(_operator.div, 1, operands[0])
1359
elif exponent == 0.5:
1360
from sage.functions.all import sqrt
1361
return self.etb.call(sqrt, operands[0])
1362
elif exponent == -0.5:
1363
from sage.functions.all import sqrt
1364
return self.etb.call(_operator.div, 1, self.etb.call(sqrt, operands[0]))
1365
elif operator is _operator.neg:
1366
return self.etb.call(operator, operands[0])
1367
return reduce(lambda x,y: self.etb.call(operator, x,y), operands)
1368
1369
def symbol(self, ex):
1370
r"""
1371
Given an ExpressionTreeBuilder, return an Expression representing
1372
this value.
1373
1374
EXAMPLES::
1375
1376
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1377
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1378
sage: x, y, z = var('x,y,z')
1379
sage: x._fast_callable_(etb)
1380
v_0
1381
sage: y._fast_callable_(etb)
1382
v_1
1383
sage: z._fast_callable_(etb)
1384
Traceback (most recent call last):
1385
...
1386
ValueError: Variable 'z' not found
1387
"""
1388
return self.etb.var(SR(ex))
1389
1390
def composition(self, ex, function):
1391
r"""
1392
Given an ExpressionTreeBuilder, return an Expression representing
1393
this value.
1394
1395
EXAMPLES::
1396
1397
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1398
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1399
sage: x,y = var('x,y')
1400
sage: sin(sqrt(x+y))._fast_callable_(etb)
1401
sin(sqrt(add(v_0, v_1)))
1402
sage: arctan2(x,y)._fast_callable_(etb)
1403
{arctan2}(v_0, v_1)
1404
"""
1405
return self.etb.call(function, *ex.operands())
1406
1407
1408
def fast_callable(ex, etb):
1409
"""
1410
Given an ExpressionTreeBuilder *etb*, return an Expression representing
1411
the symbolic expression *ex*.
1412
1413
EXAMPLES::
1414
1415
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1416
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1417
sage: x,y = var('x,y')
1418
sage: f = y+2*x^2
1419
sage: f._fast_callable_(etb)
1420
add(mul(ipow(v_0, 2), 2), v_1)
1421
1422
sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))
1423
sage: f._fast_callable_(etb)
1424
div(add(add(mul(ipow(v_0, 3), 2), mul(v_0, 2)), -1), mul(add(v_0, -2), add(v_0, 1)))
1425
1426
"""
1427
return FastCallableConverter(ex, etb)()
1428
1429
class RingConverter(Converter):
1430
def __init__(self, R, subs_dict=None):
1431
"""
1432
A class to convert expressions to other rings.
1433
1434
EXAMPLES::
1435
1436
sage: from sage.symbolic.expression_conversions import RingConverter
1437
sage: R = RingConverter(RIF, subs_dict={x:2})
1438
sage: R.ring
1439
Real Interval Field with 53 bits of precision
1440
sage: R.subs_dict
1441
{x: 2}
1442
sage: R(pi+e)
1443
5.85987448204884?
1444
sage: loads(dumps(R))
1445
<sage.symbolic.expression_conversions.RingConverter object at 0x...>
1446
"""
1447
self.subs_dict = {} if subs_dict is None else subs_dict
1448
self.ring = R
1449
1450
def symbol(self, ex):
1451
"""
1452
All symbols appearing in the expression must appear in *subs_dict*
1453
in order for the conversion to be successful.
1454
1455
EXAMPLES::
1456
1457
sage: from sage.symbolic.expression_conversions import RingConverter
1458
sage: R = RingConverter(RIF, subs_dict={x:2})
1459
sage: R(x+pi)
1460
5.141592653589794?
1461
1462
sage: R = RingConverter(RIF)
1463
sage: R(x+pi)
1464
Traceback (most recent call last):
1465
...
1466
TypeError
1467
"""
1468
try:
1469
return self.ring(self.subs_dict[ex])
1470
except KeyError:
1471
raise TypeError
1472
1473
def pyobject(self, ex, obj):
1474
"""
1475
EXAMPLES::
1476
1477
sage: from sage.symbolic.expression_conversions import RingConverter
1478
sage: R = RingConverter(RIF)
1479
sage: R(SR(5/2))
1480
2.5000000000000000?
1481
"""
1482
return self.ring(obj)
1483
1484
def arithmetic(self, ex, operator):
1485
"""
1486
EXAMPLES::
1487
1488
sage: from sage.symbolic.expression_conversions import RingConverter
1489
sage: P.<z> = ZZ[]
1490
sage: R = RingConverter(P, subs_dict={x:z})
1491
sage: a = 2*x^2 + x + 3
1492
sage: R(a)
1493
2*z^2 + z + 3
1494
"""
1495
if operator not in [_operator.add, _operator.mul, _operator.pow]:
1496
raise TypeError
1497
1498
operands = ex.operands()
1499
if operator is _operator.pow:
1500
from sage.all import Integer, Rational
1501
base, expt = operands
1502
1503
if expt == Rational(((1,2))):
1504
from sage.functions.all import sqrt
1505
return sqrt(self(base))
1506
try:
1507
expt = Integer(expt)
1508
except TypeError:
1509
pass
1510
1511
base = self(base)
1512
return base ** expt
1513
else:
1514
return reduce(operator, map(self, operands))
1515
1516
def composition(self, ex, operator):
1517
"""
1518
EXAMPLES::
1519
1520
sage: from sage.symbolic.expression_conversions import RingConverter
1521
sage: R = RingConverter(RIF)
1522
sage: R(cos(2))
1523
-0.4161468365471424?
1524
"""
1525
res = operator(*map(self, ex.operands()))
1526
if res.parent() is not self.ring:
1527
raise TypeError
1528
else:
1529
return res
1530
1531
class SubstituteFunction(Converter):
1532
def __init__(self, ex, original, new):
1533
"""
1534
A class that walks the tree and replaces occurrences of a
1535
function with another.
1536
1537
EXAMPLES::
1538
1539
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1540
sage: foo = function('foo'); bar = function('bar')
1541
sage: s = SubstituteFunction(foo(x), foo, bar)
1542
sage: s(1/foo(foo(x)) + foo(2))
1543
1/bar(bar(x)) + bar(2)
1544
"""
1545
self.original = original
1546
self.new = new
1547
self.ex = ex
1548
1549
def symbol(self, ex):
1550
"""
1551
EXAMPLES::
1552
1553
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1554
sage: foo = function('foo'); bar = function('bar')
1555
sage: s = SubstituteFunction(foo(x), foo, bar)
1556
sage: s.symbol(x)
1557
x
1558
"""
1559
return ex
1560
1561
def pyobject(self, ex, obj):
1562
"""
1563
EXAMPLES::
1564
1565
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1566
sage: foo = function('foo'); bar = function('bar')
1567
sage: s = SubstituteFunction(foo(x), foo, bar)
1568
sage: f = SR(2)
1569
sage: s.pyobject(f, f.pyobject())
1570
2
1571
sage: _.parent()
1572
Symbolic Ring
1573
"""
1574
return ex
1575
1576
def relation(self, ex, operator):
1577
"""
1578
EXAMPLES::
1579
1580
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1581
sage: foo = function('foo'); bar = function('bar')
1582
sage: s = SubstituteFunction(foo(x), foo, bar)
1583
sage: eq = foo(x) == x
1584
sage: s.relation(eq, eq.operator())
1585
bar(x) == x
1586
"""
1587
return operator(self(ex.lhs()), self(ex.rhs()))
1588
1589
def arithmetic(self, ex, operator):
1590
"""
1591
EXAMPLES::
1592
1593
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1594
sage: foo = function('foo'); bar = function('bar')
1595
sage: s = SubstituteFunction(foo(x), foo, bar)
1596
sage: f = x*foo(x) + pi/foo(x)
1597
sage: s.arithmetic(f, f.operator())
1598
x*bar(x) + pi/bar(x)
1599
"""
1600
return reduce(operator, map(self, ex.operands()))
1601
1602
def composition(self, ex, operator):
1603
"""
1604
EXAMPLES::
1605
1606
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1607
sage: foo = function('foo'); bar = function('bar')
1608
sage: s = SubstituteFunction(foo(x), foo, bar)
1609
sage: f = foo(x)
1610
sage: s.composition(f, f.operator())
1611
bar(x)
1612
sage: f = foo(foo(x))
1613
sage: s.composition(f, f.operator())
1614
bar(bar(x))
1615
sage: f = sin(foo(x))
1616
sage: s.composition(f, f.operator())
1617
sin(bar(x))
1618
sage: f = foo(sin(x))
1619
sage: s.composition(f, f.operator())
1620
bar(sin(x))
1621
"""
1622
if operator == self.original:
1623
return self.new(*map(self, ex.operands()))
1624
else:
1625
return operator(*map(self, ex.operands()))
1626
1627
def derivative(self, ex, operator):
1628
"""
1629
EXAMPLES::
1630
1631
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1632
sage: foo = function('foo'); bar = function('bar')
1633
sage: s = SubstituteFunction(foo(x), foo, bar)
1634
sage: f = foo(x).diff(x)
1635
sage: s.derivative(f, f.operator())
1636
D[0](bar)(x)
1637
1638
TESTS:
1639
1640
We can substitute functions under a derivative operator,
1641
:trac:`12801`::
1642
1643
sage: f = function('f')
1644
sage: g = function('g')
1645
sage: f(g(x)).diff(x).substitute_function(g, sin)
1646
cos(x)*D[0](f)(sin(x))
1647
1648
"""
1649
if operator.function() == self.original:
1650
return operator.change_function(self.new)(*map(self,ex.operands()))
1651
else:
1652
return operator(*map(self, ex.operands()))
1653
1654