Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/symbolic/expression_conversions.py
8817 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 + 1, x - 2], <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
1087
function-call syntax and unnamed arguments is deprecated
1088
and will be removed from a future release of Sage; you
1089
can use named arguments instead, like EXPR(x=..., y=...)
1090
See http://trac.sagemath.org/5930 for details.
1091
sage: f(1.2)
1092
1.2
1093
1094
Using _fast_float_ on a function which is the identity is
1095
now supported (see Trac 10246)::
1096
1097
sage: f = symbolic_expression(x).function(x)
1098
sage: f._fast_float_(x)
1099
<sage.ext.fast_eval.FastDoubleFunc object at ...>
1100
sage: f(22)
1101
22
1102
"""
1103
self.ex = ex
1104
1105
if vars == ():
1106
try:
1107
vars = ex.arguments()
1108
except AttributeError:
1109
vars = ex.variables()
1110
1111
if vars:
1112
from sage.misc.superseded import deprecation
1113
deprecation(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=...)")
1114
1115
1116
self.vars = vars
1117
1118
import sage.ext.fast_eval as fast_float
1119
self.ff = fast_float
1120
1121
Converter.__init__(self, use_fake_div=True)
1122
1123
def relation(self, ex, operator):
1124
"""
1125
EXAMPLES::
1126
1127
sage: ff = fast_float(x == 2, 'x')
1128
sage: ff(2)
1129
0.0
1130
sage: ff(4)
1131
2.0
1132
sage: ff = fast_float(x < 2, 'x')
1133
Traceback (most recent call last):
1134
...
1135
NotImplementedError
1136
"""
1137
if operator is not _operator.eq:
1138
raise NotImplementedError
1139
return self(ex.lhs() - ex.rhs())
1140
1141
def pyobject(self, ex, obj):
1142
"""
1143
EXAMPLES::
1144
1145
sage: f = SR(2)._fast_float_()
1146
sage: f(3)
1147
2.0
1148
"""
1149
try:
1150
return obj._fast_float_(*self.vars)
1151
except AttributeError:
1152
return self.ff.fast_float_constant(float(obj))
1153
1154
def symbol(self, ex):
1155
r"""
1156
EXAMPLES::
1157
1158
sage: f = x._fast_float_('x', 'y')
1159
sage: f(1,2)
1160
1.0
1161
sage: f = x._fast_float_('y', 'x')
1162
sage: f(1,2)
1163
2.0
1164
"""
1165
if self.vars == ():
1166
return self.ff.fast_float_arg(0)
1167
1168
vars = list(self.vars)
1169
name = repr(ex)
1170
if name in vars:
1171
return self.ff.fast_float_arg(vars.index(name))
1172
svars = [repr(x) for x in vars]
1173
if name in svars:
1174
return self.ff.fast_float_arg(svars.index(name))
1175
1176
if ex.is_symbol(): # case of callable function which is the variable, like f(x)=x
1177
name = repr(SR(ex)) # this gets back just the 'output' of the function
1178
if name in svars:
1179
return self.ff.fast_float_arg(svars.index(name))
1180
1181
try:
1182
return self.ff.fast_float_constant(float(ex))
1183
except TypeError:
1184
raise ValueError, "free variable: %s" % repr(ex)
1185
1186
def arithmetic(self, ex, operator):
1187
"""
1188
EXAMPLES::
1189
1190
sage: x,y = var('x,y')
1191
sage: f = x*x-y
1192
sage: ff = f._fast_float_('x','y')
1193
sage: ff(2,3)
1194
1.0
1195
1196
sage: a = x + 2*y
1197
sage: f = a._fast_float_('x', 'y')
1198
sage: f(1,0)
1199
1.0
1200
sage: f(0,1)
1201
2.0
1202
1203
sage: f = sqrt(x)._fast_float_('x'); f.op_list()
1204
['load 0', 'call sqrt(1)']
1205
1206
sage: f = (1/2*x)._fast_float_('x'); f.op_list()
1207
['load 0', 'push 0.5', 'mul']
1208
"""
1209
operands = ex.operands()
1210
if operator is _operator.neg:
1211
return operator(self(operands[0]))
1212
1213
from sage.rings.all import Rational
1214
if operator is _operator.pow and operands[1] == Rational(((1,2))):
1215
from sage.functions.all import sqrt
1216
return sqrt(self(operands[0]))
1217
fops = map(self, operands)
1218
return reduce(operator, fops)
1219
1220
def composition(self, ex, operator):
1221
"""
1222
EXAMPLES::
1223
1224
sage: f = sqrt(x)._fast_float_('x')
1225
sage: f(2)
1226
1.41421356237309...
1227
sage: y = var('y')
1228
sage: f = sqrt(x+y)._fast_float_('x', 'y')
1229
sage: f(1,1)
1230
1.41421356237309...
1231
1232
::
1233
1234
sage: f = sqrt(x+2*y)._fast_float_('x', 'y')
1235
sage: f(2,0)
1236
1.41421356237309...
1237
sage: f(0,1)
1238
1.41421356237309...
1239
"""
1240
f = operator
1241
g = map(self, ex.operands())
1242
try:
1243
return f(*g)
1244
except TypeError:
1245
from sage.functions.other import abs_symbolic
1246
if f is abs_symbolic:
1247
return abs(*g) # special case
1248
else:
1249
return self.ff.fast_float_func(f, *g)
1250
1251
def fast_float(ex, *vars):
1252
"""
1253
Returns an object which provides fast floating point evaluation of
1254
the symbolic expression *ex*.
1255
1256
See :mod:`sage.ext.fast_eval` for more information.
1257
1258
EXAMPLES::
1259
1260
sage: from sage.symbolic.expression_conversions import fast_float
1261
sage: f = sqrt(x+1)
1262
sage: ff = fast_float(f, 'x')
1263
sage: ff(1.0)
1264
1.4142135623730951
1265
"""
1266
return FastFloatConverter(ex, *vars)()
1267
1268
#################
1269
# Fast Callable #
1270
#################
1271
1272
class FastCallableConverter(Converter):
1273
def __init__(self, ex, etb):
1274
"""
1275
EXAMPLES::
1276
1277
sage: from sage.symbolic.expression_conversions import FastCallableConverter
1278
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1279
sage: etb = ExpressionTreeBuilder(vars=['x'])
1280
sage: f = FastCallableConverter(x+2, etb)
1281
sage: f.ex
1282
x + 2
1283
sage: f.etb
1284
<sage.ext.fast_callable.ExpressionTreeBuilder object at 0x...>
1285
sage: f.use_fake_div
1286
True
1287
"""
1288
self.ex = ex
1289
self.etb = etb
1290
Converter.__init__(self, use_fake_div=True)
1291
1292
def pyobject(self, ex, obj):
1293
r"""
1294
EXAMPLES::
1295
1296
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1297
sage: etb = ExpressionTreeBuilder(vars=['x'])
1298
sage: pi._fast_callable_(etb)
1299
pi
1300
sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1301
sage: pi._fast_callable_(etb)
1302
3.14159265359
1303
"""
1304
from sage.symbolic.constants import Constant
1305
if isinstance(obj, Constant):
1306
obj = obj.expression()
1307
return self.etb.constant(obj)
1308
1309
def relation(self, ex, operator):
1310
"""
1311
EXAMPLES::
1312
1313
sage: ff = fast_callable(x == 2, vars=['x'])
1314
sage: ff(2)
1315
0
1316
sage: ff(4)
1317
2
1318
sage: ff = fast_callable(x < 2, vars=['x'])
1319
Traceback (most recent call last):
1320
...
1321
NotImplementedError
1322
"""
1323
if operator is not _operator.eq:
1324
raise NotImplementedError
1325
return self(ex.lhs() - ex.rhs())
1326
1327
def arithmetic(self, ex, operator):
1328
r"""
1329
EXAMPLES::
1330
1331
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1332
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1333
sage: var('x,y')
1334
(x, y)
1335
sage: (x+y)._fast_callable_(etb)
1336
add(v_0, v_1)
1337
sage: (-x)._fast_callable_(etb)
1338
neg(v_0)
1339
sage: (x+y+x^2)._fast_callable_(etb)
1340
add(add(ipow(v_0, 2), v_0), v_1)
1341
1342
TESTS:
1343
1344
Check if rational functions with numerator 1 can be converted. #8056::
1345
1346
sage: (1/pi/x)._fast_callable_(etb)
1347
div(1, mul(pi, v_0))
1348
1349
sage: etb = ExpressionTreeBuilder(vars=['x'], domain=RDF)
1350
sage: (x^7)._fast_callable_(etb)
1351
ipow(v_0, 7)
1352
sage: f(x)=1/pi/x; plot(f,2,3)
1353
"""
1354
# This used to convert the operands first. Doing it this way
1355
# instead gives a chance to notice powers with an integer
1356
# exponent before the exponent gets (potentially) converted
1357
# to another type.
1358
operands = ex.operands()
1359
if operator is _operator.pow:
1360
exponent = operands[1]
1361
if exponent == -1:
1362
return self.etb.call(_operator.div, 1, operands[0])
1363
elif exponent == 0.5:
1364
from sage.functions.all import sqrt
1365
return self.etb.call(sqrt, operands[0])
1366
elif exponent == -0.5:
1367
from sage.functions.all import sqrt
1368
return self.etb.call(_operator.div, 1, self.etb.call(sqrt, operands[0]))
1369
elif operator is _operator.neg:
1370
return self.etb.call(operator, operands[0])
1371
return reduce(lambda x,y: self.etb.call(operator, x,y), operands)
1372
1373
def symbol(self, ex):
1374
r"""
1375
Given an ExpressionTreeBuilder, return an Expression representing
1376
this value.
1377
1378
EXAMPLES::
1379
1380
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1381
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1382
sage: x, y, z = var('x,y,z')
1383
sage: x._fast_callable_(etb)
1384
v_0
1385
sage: y._fast_callable_(etb)
1386
v_1
1387
sage: z._fast_callable_(etb)
1388
Traceback (most recent call last):
1389
...
1390
ValueError: Variable 'z' not found
1391
"""
1392
return self.etb.var(SR(ex))
1393
1394
def composition(self, ex, function):
1395
r"""
1396
Given an ExpressionTreeBuilder, return an Expression representing
1397
this value.
1398
1399
EXAMPLES::
1400
1401
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1402
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1403
sage: x,y = var('x,y')
1404
sage: sin(sqrt(x+y))._fast_callable_(etb)
1405
sin(sqrt(add(v_0, v_1)))
1406
sage: arctan2(x,y)._fast_callable_(etb)
1407
{arctan2}(v_0, v_1)
1408
"""
1409
return self.etb.call(function, *ex.operands())
1410
1411
1412
def fast_callable(ex, etb):
1413
"""
1414
Given an ExpressionTreeBuilder *etb*, return an Expression representing
1415
the symbolic expression *ex*.
1416
1417
EXAMPLES::
1418
1419
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
1420
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
1421
sage: x,y = var('x,y')
1422
sage: f = y+2*x^2
1423
sage: f._fast_callable_(etb)
1424
add(mul(ipow(v_0, 2), 2), v_1)
1425
1426
sage: f = (2*x^3+2*x-1)/((x-2)*(x+1))
1427
sage: f._fast_callable_(etb)
1428
div(add(add(mul(ipow(v_0, 3), 2), mul(v_0, 2)), -1), mul(add(v_0, 1), add(v_0, -2)))
1429
1430
"""
1431
return FastCallableConverter(ex, etb)()
1432
1433
class RingConverter(Converter):
1434
def __init__(self, R, subs_dict=None):
1435
"""
1436
A class to convert expressions to other rings.
1437
1438
EXAMPLES::
1439
1440
sage: from sage.symbolic.expression_conversions import RingConverter
1441
sage: R = RingConverter(RIF, subs_dict={x:2})
1442
sage: R.ring
1443
Real Interval Field with 53 bits of precision
1444
sage: R.subs_dict
1445
{x: 2}
1446
sage: R(pi+e)
1447
5.85987448204884?
1448
sage: loads(dumps(R))
1449
<sage.symbolic.expression_conversions.RingConverter object at 0x...>
1450
"""
1451
self.subs_dict = {} if subs_dict is None else subs_dict
1452
self.ring = R
1453
1454
def symbol(self, ex):
1455
"""
1456
All symbols appearing in the expression must appear in *subs_dict*
1457
in order for the conversion to be successful.
1458
1459
EXAMPLES::
1460
1461
sage: from sage.symbolic.expression_conversions import RingConverter
1462
sage: R = RingConverter(RIF, subs_dict={x:2})
1463
sage: R(x+pi)
1464
5.141592653589794?
1465
1466
sage: R = RingConverter(RIF)
1467
sage: R(x+pi)
1468
Traceback (most recent call last):
1469
...
1470
TypeError
1471
"""
1472
try:
1473
return self.ring(self.subs_dict[ex])
1474
except KeyError:
1475
raise TypeError
1476
1477
def pyobject(self, ex, obj):
1478
"""
1479
EXAMPLES::
1480
1481
sage: from sage.symbolic.expression_conversions import RingConverter
1482
sage: R = RingConverter(RIF)
1483
sage: R(SR(5/2))
1484
2.5000000000000000?
1485
"""
1486
return self.ring(obj)
1487
1488
def arithmetic(self, ex, operator):
1489
"""
1490
EXAMPLES::
1491
1492
sage: from sage.symbolic.expression_conversions import RingConverter
1493
sage: P.<z> = ZZ[]
1494
sage: R = RingConverter(P, subs_dict={x:z})
1495
sage: a = 2*x^2 + x + 3
1496
sage: R(a)
1497
2*z^2 + z + 3
1498
"""
1499
if operator not in [_operator.add, _operator.mul, _operator.pow]:
1500
raise TypeError
1501
1502
operands = ex.operands()
1503
if operator is _operator.pow:
1504
from sage.all import Integer, Rational
1505
base, expt = operands
1506
1507
if expt == Rational(((1,2))):
1508
from sage.functions.all import sqrt
1509
return sqrt(self(base))
1510
try:
1511
expt = Integer(expt)
1512
except TypeError:
1513
pass
1514
1515
base = self(base)
1516
return base ** expt
1517
else:
1518
return reduce(operator, map(self, operands))
1519
1520
def composition(self, ex, operator):
1521
"""
1522
EXAMPLES::
1523
1524
sage: from sage.symbolic.expression_conversions import RingConverter
1525
sage: R = RingConverter(RIF)
1526
sage: R(cos(2))
1527
-0.4161468365471424?
1528
"""
1529
res = operator(*map(self, ex.operands()))
1530
if res.parent() is not self.ring:
1531
raise TypeError
1532
else:
1533
return res
1534
1535
class SubstituteFunction(Converter):
1536
def __init__(self, ex, original, new):
1537
"""
1538
A class that walks the tree and replaces occurrences of a
1539
function with another.
1540
1541
EXAMPLES::
1542
1543
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1544
sage: foo = function('foo'); bar = function('bar')
1545
sage: s = SubstituteFunction(foo(x), foo, bar)
1546
sage: s(1/foo(foo(x)) + foo(2))
1547
1/bar(bar(x)) + bar(2)
1548
"""
1549
self.original = original
1550
self.new = new
1551
self.ex = ex
1552
1553
def symbol(self, ex):
1554
"""
1555
EXAMPLES::
1556
1557
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1558
sage: foo = function('foo'); bar = function('bar')
1559
sage: s = SubstituteFunction(foo(x), foo, bar)
1560
sage: s.symbol(x)
1561
x
1562
"""
1563
return ex
1564
1565
def pyobject(self, ex, obj):
1566
"""
1567
EXAMPLES::
1568
1569
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1570
sage: foo = function('foo'); bar = function('bar')
1571
sage: s = SubstituteFunction(foo(x), foo, bar)
1572
sage: f = SR(2)
1573
sage: s.pyobject(f, f.pyobject())
1574
2
1575
sage: _.parent()
1576
Symbolic Ring
1577
"""
1578
return ex
1579
1580
def relation(self, ex, operator):
1581
"""
1582
EXAMPLES::
1583
1584
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1585
sage: foo = function('foo'); bar = function('bar')
1586
sage: s = SubstituteFunction(foo(x), foo, bar)
1587
sage: eq = foo(x) == x
1588
sage: s.relation(eq, eq.operator())
1589
bar(x) == x
1590
"""
1591
return operator(self(ex.lhs()), self(ex.rhs()))
1592
1593
def arithmetic(self, ex, operator):
1594
"""
1595
EXAMPLES::
1596
1597
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1598
sage: foo = function('foo'); bar = function('bar')
1599
sage: s = SubstituteFunction(foo(x), foo, bar)
1600
sage: f = x*foo(x) + pi/foo(x)
1601
sage: s.arithmetic(f, f.operator())
1602
x*bar(x) + pi/bar(x)
1603
"""
1604
return reduce(operator, map(self, ex.operands()))
1605
1606
def composition(self, ex, operator):
1607
"""
1608
EXAMPLES::
1609
1610
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1611
sage: foo = function('foo'); bar = function('bar')
1612
sage: s = SubstituteFunction(foo(x), foo, bar)
1613
sage: f = foo(x)
1614
sage: s.composition(f, f.operator())
1615
bar(x)
1616
sage: f = foo(foo(x))
1617
sage: s.composition(f, f.operator())
1618
bar(bar(x))
1619
sage: f = sin(foo(x))
1620
sage: s.composition(f, f.operator())
1621
sin(bar(x))
1622
sage: f = foo(sin(x))
1623
sage: s.composition(f, f.operator())
1624
bar(sin(x))
1625
"""
1626
if operator == self.original:
1627
return self.new(*map(self, ex.operands()))
1628
else:
1629
return operator(*map(self, ex.operands()))
1630
1631
def derivative(self, ex, operator):
1632
"""
1633
EXAMPLES::
1634
1635
sage: from sage.symbolic.expression_conversions import SubstituteFunction
1636
sage: foo = function('foo'); bar = function('bar')
1637
sage: s = SubstituteFunction(foo(x), foo, bar)
1638
sage: f = foo(x).diff(x)
1639
sage: s.derivative(f, f.operator())
1640
D[0](bar)(x)
1641
1642
TESTS:
1643
1644
We can substitute functions under a derivative operator,
1645
:trac:`12801`::
1646
1647
sage: f = function('f')
1648
sage: g = function('g')
1649
sage: f(g(x)).diff(x).substitute_function(g, sin)
1650
cos(x)*D[0](f)(sin(x))
1651
1652
"""
1653
if operator.function() == self.original:
1654
return operator.change_function(self.new)(*map(self,ex.operands()))
1655
else:
1656
return operator(*map(self, ex.operands()))
1657
1658