Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/symbolic/function.pyx
8815 views
1
###############################################################################
2
# Sage: Open Source Mathematical Software
3
# Copyright (C) 2008 - 2010 Burcin Erocal <[email protected]>
4
# Copyright (C) 2008 William Stein <[email protected]>
5
# Distributed under the terms of the GNU General Public License (GPL),
6
# version 2 or any later version. The full text of the GPL is available at:
7
# http://www.gnu.org/licenses/
8
###############################################################################
9
10
r"""
11
12
Support for symbolic functions.
13
14
"""
15
include "sage/ext/interrupt.pxi"
16
include "sage/ext/cdefs.pxi"
17
18
from ginac cimport *
19
20
from sage.structure.sage_object cimport SageObject
21
from expression cimport new_Expression_from_GEx, Expression
22
from ring import SR
23
24
from sage.structure.parent cimport Parent
25
from sage.structure.coerce import parent
26
from sage.structure.element import get_coercion_model
27
28
# we keep a database of symbolic functions initialized in a session
29
# this also makes the .operator() method of symbolic expressions work
30
cdef dict sfunction_serial_dict = {}
31
32
from sage.misc.fpickle import pickle_function, unpickle_function
33
from sage.ext.fast_eval import FastDoubleFunc
34
35
# List of functions which ginac allows us to define custom behavior for.
36
# Changing the order of this list could cause problems unpickling old pickles.
37
sfunctions_funcs = ['eval', 'evalf', 'conjugate', 'real_part', 'imag_part',
38
'derivative', 'power', 'series', 'print', 'print_latex', 'tderivative']
39
40
cdef class Function(SageObject):
41
"""
42
Base class for symbolic functions defined through Pynac in Sage.
43
44
This is an abstract base class, with generic code for the interfaces
45
and a :meth:`__call__` method. Subclasses should implement the
46
:meth:`_is_registered` and :meth:`_register_function` methods.
47
48
This class is not intended for direct use, instead use one of the
49
subclasses :class:`BuiltinFunction` or :class:`SymbolicFunction`.
50
"""
51
def __init__(self, name, nargs, latex_name=None, conversions=None,
52
evalf_params_first=True, alt_name=None):
53
"""
54
This is an abstract base class. It's not possible to test it directly.
55
56
EXAMPLES::
57
58
sage: f = function('f', nargs=1, conjugate_func=lambda self,x: 2r*x) # indirect doctest
59
sage: f(2)
60
f(2)
61
sage: f(2).conjugate()
62
4
63
64
TESTS::
65
66
# eval_func raises exception
67
sage: def ef(self, x): raise RuntimeError, "foo"
68
sage: bar = function("bar", nargs=1, eval_func=ef)
69
sage: bar(x)
70
Traceback (most recent call last):
71
...
72
RuntimeError: foo
73
74
# eval_func returns non coercible
75
sage: def ef(self, x): return ZZ
76
sage: bar = function("bar", nargs=1, eval_func=ef)
77
sage: bar(x)
78
Traceback (most recent call last):
79
...
80
TypeError: function did not return a symbolic expression or an element that can be coerced into a symbolic expression
81
82
# eval_func is not callable
83
sage: bar = function("bar", nargs=1, eval_func=5)
84
Traceback (most recent call last):
85
...
86
ValueError: eval_func parameter must be callable
87
"""
88
self._name = name
89
self._alt_name = alt_name
90
self._nargs = nargs
91
self._latex_name = latex_name
92
self._evalf_params_first = evalf_params_first
93
self._conversions = {} if conversions is None else conversions
94
95
# handle custom printing
96
# if print_func is defined, it is used instead of name
97
# latex printing can be customised either by setting a string latex_name
98
# or giving a custom function argument print_latex_func
99
if latex_name and hasattr(self, '_print_latex_'):
100
raise ValueError, "only one of latex_name or _print_latex_ should be specified."
101
102
# only one of derivative and tderivative should be defined
103
if hasattr(self, '_derivative_') and hasattr(self, '_tderivative_'):
104
raise ValueError, "only one of _derivative_ or _tderivative_ should be defined."
105
106
for fname in sfunctions_funcs:
107
real_fname = '_%s_'%fname
108
if hasattr(self, real_fname) and not \
109
callable(getattr(self, real_fname)):
110
raise ValueError, real_fname + " parameter must be callable"
111
112
if not self._is_registered():
113
self._register_function()
114
115
global sfunction_serial_dict
116
sfunction_serial_dict[self._serial] = self
117
118
from sage.symbolic.pynac import symbol_table, register_symbol
119
symbol_table['functions'][self._name] = self
120
121
register_symbol(self, self._conversions)
122
123
cdef _is_registered(self):
124
"""
125
Check if this function is already registered. If it is, set
126
`self._serial` to the right value.
127
"""
128
raise NotImplementedError, "this is an abstract base class, it shouldn't be initialized directly"
129
130
cdef _register_function(self):
131
"""
132
133
TESTS:
134
135
After :trac:`9240`, pickling and unpickling of symbolic
136
functions was broken. We check here that this is fixed
137
(:trac:`11919`)::
138
139
sage: f = function('f', x)
140
sage: s = dumps(f)
141
sage: loads(s)
142
f(x)
143
sage: deepcopy(f)
144
f(x)
145
146
"""
147
cdef GFunctionOpt opt
148
opt = g_function_options_args(self._name, self._nargs)
149
150
if hasattr(self, '_eval_'):
151
opt.eval_func(self)
152
153
if not self._evalf_params_first:
154
opt.do_not_evalf_params()
155
156
if hasattr(self, '_evalf_'):
157
opt.evalf_func(self)
158
159
if hasattr(self, '_conjugate_'):
160
opt.conjugate_func(self)
161
162
if hasattr(self, '_real_part_'):
163
opt.real_part_func(self)
164
165
if hasattr(self, '_imag_part_'):
166
opt.imag_part_func(self)
167
168
if hasattr(self, '_derivative_'):
169
opt.derivative_func(self)
170
171
if hasattr(self, '_tderivative_'):
172
opt.do_not_apply_chain_rule()
173
opt.derivative_func(self)
174
175
if hasattr(self, '_power_'):
176
opt.power_func(self)
177
178
if hasattr(self, '_series_'):
179
opt.series_func(self)
180
181
# custom print functions are called from python
182
# so we don't register them with the ginac function_options object
183
184
if self._latex_name:
185
opt.latex_name(self._latex_name)
186
187
self._serial = g_register_new(opt)
188
g_foptions_assign(g_registered_functions().index(self._serial), opt)
189
190
def _eval_default(self, *args):
191
"""
192
Default automatic evaluation function.
193
194
Calls numeric evaluation if the argument is not exact.
195
196
TESTS::
197
198
sage: coth(5) # indirect doctest
199
coth(5)
200
sage: coth(0.5)
201
2.16395341373865
202
sage: from sage.symbolic.function import BuiltinFunction
203
sage: class Test(BuiltinFunction):
204
....: def __init__(self):
205
....: BuiltinFunction.__init__(self, 'test', nargs=2)
206
....: def _evalf_(self, x, y, parent):
207
....: return x + 1
208
....: def _eval_(self, x, y):
209
....: res = self._eval_default(x, y)
210
....: if res:
211
....: return res
212
....: elif x == 2:
213
....: return 3
214
....: else:
215
....: return
216
sage: test = Test()
217
sage: test(1.3, 4)
218
2.30000000000000
219
sage: test(pi, 4)
220
test(pi, 4)
221
sage: test(2, x)
222
3
223
sage: test(2., 4)
224
3.00000000000000
225
sage: test(1 + 1.0*I, 2)
226
2.00000000000000 + 1.00000000000000*I
227
sage: class Test2(BuiltinFunction):
228
....: def __init__(self):
229
....: BuiltinFunction.__init__(self, 'test', nargs=1)
230
....: def _evalf_(self, x, parent):
231
....: return 0.5
232
....: def _eval_(self, x):
233
....: res = self._eval_default(x)
234
....: if res:
235
....: return res
236
....: else:
237
....: return 3
238
sage: test2 = Test2()
239
sage: test2(1.3)
240
0.500000000000000
241
sage: test2(pi)
242
3
243
"""
244
if len(args) == 1:
245
x = args[0]
246
try:
247
return getattr(x, self.name())()
248
except AttributeError:
249
pass
250
if is_inexact(x) and not parent_c(x) is SR:
251
return self._evalf_(x, parent=parent(x))
252
return
253
else:
254
cc = get_coercion_model().canonical_coercion
255
coerced = reduce(lambda x, y: cc(x, y)[0], args)
256
if is_inexact(coerced) and not parent_c(coerced) is SR:
257
return self._evalf_(*args, parent=parent(coerced))
258
else:
259
return
260
261
def __hash__(self):
262
"""
263
EXAMPLES::
264
265
sage: f = function('f', nargs=1, conjugate_func=lambda self,x: 2r*x)
266
sage: f.__hash__() #random
267
-2224334885124003860
268
sage: hash(f(2)) #random
269
4168614485
270
"""
271
return hash(self._name)*(self._nargs+1)*self._serial
272
273
def __repr__(self):
274
"""
275
EXAMPLES::
276
277
sage: foo = function("foo", nargs=2); foo
278
foo
279
"""
280
return self._name
281
282
def _latex_(self):
283
r"""
284
EXAMPLES::
285
286
sage: from sage.symbolic.function import SymbolicFunction
287
sage: s = SymbolicFunction('foo'); s
288
foo
289
sage: latex(s)
290
foo
291
sage: s = SymbolicFunction('foo', latex_name=r'{\rm foo}')
292
sage: latex(s)
293
{\rm foo}
294
sage: s._latex_()
295
'{\\rm foo}'
296
"""
297
if self._latex_name is not None:
298
return self._latex_name
299
else:
300
return self._name
301
302
def __cmp__(self, other):
303
"""
304
TESTS:
305
sage: foo = function("foo", nargs=2)
306
sage: foo == foo
307
True
308
sage: foo == 2
309
False
310
sage: foo(1,2).operator() == foo
311
True
312
313
"""
314
if PY_TYPE_CHECK(other, Function):
315
return cmp(self._serial, (<Function>other)._serial)
316
return False
317
318
def __call__(self, *args, bint coerce=True, bint hold=False):
319
"""
320
Evaluates this function at the given arguments.
321
322
We coerce the arguments into symbolic expressions if coerce=True, then
323
call the Pynac evaluation method, which in turn passes the arguments to
324
a custom automatic evaluation method if ``_eval_()`` is defined.
325
326
EXAMPLES::
327
328
sage: foo = function("foo", nargs=2)
329
sage: x,y,z = var("x y z")
330
sage: foo(x,y)
331
foo(x, y)
332
333
sage: foo(y)
334
Traceback (most recent call last):
335
...
336
TypeError: Symbolic function foo takes exactly 2 arguments (1 given)
337
338
sage: bar = function("bar")
339
sage: bar(x)
340
bar(x)
341
sage: bar(x,y)
342
bar(x, y)
343
344
The `hold` argument prevents automatic evaluation of the function::
345
346
sage: exp(log(x))
347
x
348
sage: exp(log(x), hold=True)
349
e^log(x)
350
351
We can also handle numpy types::
352
353
sage: import numpy
354
sage: sin(numpy.arange(5))
355
array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ])
356
357
Symbolic functions evaluate non-exact input numerically, and return
358
symbolic expressions on exact input::
359
360
sage: arctan(1)
361
1/4*pi
362
sage: arctan(float(1))
363
0.7853981633974483
364
365
Precision of the result depends on the precision of the input::
366
367
sage: arctan(RR(1))
368
0.785398163397448
369
sage: arctan(RealField(100)(1))
370
0.78539816339744830961566084582
371
372
Return types for non-exact input depends on the input type::
373
374
sage: type(exp(float(0)))
375
<type 'float'>
376
sage: exp(RR(0)).parent()
377
Real Field with 53 bits of precision
378
379
380
TESTS:
381
382
Test coercion::
383
384
sage: bar(ZZ)
385
Traceback (most recent call last):
386
...
387
TypeError: cannot coerce arguments: ...
388
sage: exp(QQbar(I))
389
0.540302305868140 + 0.841470984807897*I
390
391
For functions with single argument, if coercion fails we try to call
392
a method with the name of the function on the object::
393
394
sage: M = matrix(SR, 2, 2, [x, 0, 0, I*pi])
395
sage: exp(M)
396
[e^x 0]
397
[ 0 -1]
398
"""
399
if self._nargs > 0 and len(args) != self._nargs:
400
raise TypeError, "Symbolic function %s takes exactly %s arguments (%s given)"%(self._name, self._nargs, len(args))
401
402
# support fast_float
403
if self._nargs == 1:
404
if isinstance(args[0], FastDoubleFunc):
405
try:
406
return getattr(args[0], self._name)()
407
except AttributeError, err:
408
raise TypeError, "cannot handle fast float arguments"
409
410
# support numpy arrays as arguments
411
if any([type(arg).__module__ == 'numpy' for arg in args]): # avoid importing
412
import numpy
413
# check that at least one of the arguments is a numpy array
414
if any([isinstance(arg, numpy.ndarray) for arg in args]):
415
try:
416
return getattr(numpy, self.name())(*args)
417
except AttributeError:
418
return self._eval_numpy_(*args)
419
420
# if the given input is a symbolic expression, we don't convert it back
421
# to a numeric type at the end
422
if len(args) == 1 and parent_c(args[0]) is SR:
423
symbolic_input = True
424
else:
425
symbolic_input = False
426
427
428
cdef Py_ssize_t i
429
if coerce:
430
try:
431
args = map(SR.coerce, args)
432
except TypeError, err:
433
# If the function takes only one argument, we try to call
434
# a method with the name of this function on the object.
435
# This makes the following work:
436
# sage: M = matrix(SR, 2, 2, [x, 0, 0, I*pi])
437
# [e^x 0]
438
# [ 0 -1]
439
if len(args) == 1:
440
try:
441
return getattr(args[0], self._name)()
442
except AttributeError:
443
pass
444
445
# There is no natural coercion from QQbar to the symbolic ring
446
# in order to support
447
# sage: QQbar(sqrt(2)) + sqrt(3)
448
# 3.146264369941973?
449
# to work around this limitation, we manually convert
450
# elements of QQbar to symbolic expressions here
451
from sage.rings.qqbar import QQbar, AA
452
nargs = [None]*len(args)
453
for i in range(len(args)):
454
carg = args[i]
455
if PY_TYPE_CHECK(carg, Element) and \
456
(<Element>carg)._parent is QQbar or \
457
(<Element>carg)._parent is AA:
458
nargs[i] = SR(carg)
459
else:
460
try:
461
nargs[i] = SR.coerce(carg)
462
except Exception:
463
raise TypeError, "cannot coerce arguments: %s"%(err)
464
args = nargs
465
else: # coerce == False
466
for a in args:
467
if not PY_TYPE_CHECK(a, Expression):
468
raise TypeError, "arguments must be symbolic expressions"
469
470
cdef GEx res
471
cdef GExVector vec
472
if self._nargs == 0 or self._nargs > 3:
473
for i from 0 <= i < len(args):
474
vec.push_back((<Expression>args[i])._gobj)
475
res = g_function_evalv(self._serial, vec, hold)
476
elif self._nargs == 1:
477
res = g_function_eval1(self._serial,
478
(<Expression>args[0])._gobj, hold)
479
elif self._nargs == 2:
480
res = g_function_eval2(self._serial, (<Expression>args[0])._gobj,
481
(<Expression>args[1])._gobj, hold)
482
elif self._nargs == 3:
483
res = g_function_eval3(self._serial,
484
(<Expression>args[0])._gobj, (<Expression>args[1])._gobj,
485
(<Expression>args[2])._gobj, hold)
486
487
488
if not symbolic_input and is_a_numeric(res):
489
return py_object_from_numeric(res)
490
491
return new_Expression_from_GEx(SR, res)
492
493
def name(self):
494
"""
495
Returns the name of this function.
496
497
EXAMPLES::
498
499
sage: foo = function("foo", nargs=2)
500
sage: foo.name()
501
'foo'
502
"""
503
return self._name
504
505
def number_of_arguments(self):
506
"""
507
Returns the number of arguments that this function takes.
508
509
EXAMPLES::
510
511
sage: foo = function("foo", nargs=2)
512
sage: foo.number_of_arguments()
513
2
514
sage: foo(x,x)
515
foo(x, x)
516
517
sage: foo(x)
518
Traceback (most recent call last):
519
...
520
TypeError: Symbolic function foo takes exactly 2 arguments (1 given)
521
"""
522
return self._nargs
523
524
def variables(self):
525
"""
526
Returns the variables (of which there are none) present in
527
this SFunction.
528
529
EXAMPLES::
530
531
sage: sin.variables()
532
()
533
"""
534
return ()
535
536
def default_variable(self):
537
"""
538
Returns a default variable.
539
540
EXAMPLES::
541
542
sage: sin.default_variable()
543
x
544
"""
545
return SR.var('x')
546
547
def _interface_init_(self, I=None):
548
"""
549
EXAMPLES::
550
551
sage: sin._interface_init_(maxima)
552
'sin'
553
"""
554
if I is None:
555
return self._name
556
return self._conversions.get(I.name(), self._name)
557
558
def _mathematica_init_(self):
559
"""
560
EXAMPLES::
561
562
sage: sin._mathematica_init_()
563
'Sin'
564
sage: exp._mathematica_init_()
565
'Exp'
566
sage: (exp(x) + sin(x) + tan(x))._mathematica_init_()
567
'(Exp[x])+(Sin[x])+(Tan[x])'
568
"""
569
s = self._conversions.get('mathematica', None)
570
return s if s is not None else repr(self).capitalize()
571
572
def _sympy_init_(self, I=None):
573
"""
574
EXAMPLES::
575
576
sage: arcsin._sympy_init_()
577
'asin'
578
sage: from sage.symbolic.function import SymbolicFunction
579
sage: g = SymbolicFunction('g', conversions=dict(sympy='gg'))
580
sage: g._sympy_init_()
581
'gg'
582
sage: g(x)._sympy_()
583
Traceback (most recent call last):
584
...
585
NotImplementedError: SymPy function 'gg' doesn't exist
586
"""
587
return self._conversions.get('sympy', self._name)
588
589
def _maxima_init_(self, I=None):
590
"""
591
EXAMPLES::
592
593
sage: exp._maxima_init_()
594
'exp'
595
sage: from sage.symbolic.function import SymbolicFunction
596
sage: f = SymbolicFunction('f', latex_name='f', conversions=dict(maxima='ff'))
597
sage: f._maxima_init_()
598
'ff'
599
"""
600
return self._conversions.get('maxima', self._name)
601
602
def _fast_float_(self, *vars):
603
"""
604
Returns an object which provides fast floating point evaluation of
605
self.
606
607
See sage.ext.fast_eval? for more information.
608
609
EXAMPLES::
610
611
sage: sin._fast_float_()
612
<sage.ext.fast_eval.FastDoubleFunc object at 0x...>
613
sage: sin._fast_float_()(0)
614
0.0
615
616
::
617
618
sage: ff = cos._fast_float_(); ff
619
<sage.ext.fast_eval.FastDoubleFunc object at 0x...>
620
sage: ff.is_pure_c()
621
True
622
sage: ff(0)
623
1.0
624
625
::
626
627
sage: ff = erf._fast_float_()
628
sage: ff.is_pure_c()
629
False
630
sage: ff(1.5)
631
0.9661051464753108
632
sage: erf(1.5)
633
0.966105146475311
634
"""
635
import sage.ext.fast_eval as fast_float
636
637
args = [fast_float.fast_float_arg(n) for n in range(self.number_of_arguments())]
638
try:
639
return self(*args)
640
except TypeError, err:
641
return fast_float.fast_float_func(self, *args)
642
643
def _fast_callable_(self, etb):
644
r"""
645
Given an ExpressionTreeBuilder, return an Expression representing
646
this value.
647
648
EXAMPLES::
649
650
sage: from sage.ext.fast_callable import ExpressionTreeBuilder
651
sage: etb = ExpressionTreeBuilder(vars=['x','y'])
652
sage: sin._fast_callable_(etb)
653
sin(v_0)
654
sage: erf._fast_callable_(etb)
655
{erf}(v_0)
656
"""
657
args = [etb._var_number(n) for n in range(self.number_of_arguments())]
658
return etb.call(self, *args)
659
660
def _eval_numpy_(self, *args):
661
r"""
662
Evaluates this function at the given arguments.
663
664
At least one of elements of args is supposed to be a numpy array.
665
666
EXAMPLES::
667
668
sage: import numpy
669
sage: a = numpy.arange(5)
670
sage: csc(a)
671
doctest:270: RuntimeWarning: divide by zero encountered in divide
672
array([ inf, 1.18839511, 1.09975017, 7.0861674 , -1.32134871])
673
674
sage: factorial(a)
675
Traceback (most recent call last):
676
...
677
NotImplementedError: The Function factorial does not support numpy arrays as arguments
678
"""
679
raise NotImplementedError("The Function %s does not support numpy arrays as arguments" % self.name())
680
681
cdef class GinacFunction(BuiltinFunction):
682
"""
683
This class provides a wrapper around symbolic functions already defined in
684
Pynac/GiNaC.
685
686
GiNaC provides custom methods for these functions defined at the C++ level.
687
It is still possible to define new custom functionality or override those
688
already defined.
689
690
There is also no need to register these functions.
691
"""
692
def __init__(self, name, nargs=1, latex_name=None, conversions=None,
693
ginac_name=None, evalf_params_first=True):
694
"""
695
TESTS::
696
697
sage: from sage.functions.trig import Function_sin
698
sage: s = Function_sin() # indirect doctest
699
sage: s(0)
700
0
701
sage: s(pi)
702
0
703
sage: s(pi/2)
704
1
705
"""
706
self._ginac_name = ginac_name
707
BuiltinFunction.__init__(self, name, nargs, latex_name, conversions,
708
evalf_params_first=evalf_params_first)
709
710
cdef _is_registered(self):
711
# Since this is function is defined in C++, it is already in
712
# ginac's function registry
713
fname = self._ginac_name if self._ginac_name is not None else self._name
714
# get serial
715
try:
716
self._serial = find_function(fname, self._nargs)
717
except ValueError, err:
718
raise ValueError, "cannot find GiNaC function with name %s and %s arguments"%(fname, self._nargs)
719
720
global sfunction_serial_dict
721
return sfunction_serial_dict.has_key(self._serial)
722
723
cdef _register_function(self):
724
# We don't need to add anything to GiNaC's function registry
725
# However, if any custom methods were provided in the python class,
726
# we should set the properties of the function_options object
727
# corresponding to this function
728
cdef GFunctionOpt opt = g_registered_functions().index(self._serial)
729
730
if hasattr(self, '_eval_'):
731
opt.eval_func(self)
732
733
if not self._evalf_params_first:
734
opt.do_not_evalf_params()
735
736
if hasattr(self, '_evalf_'):
737
opt.evalf_func(self)
738
739
if hasattr(self, '_conjugate_'):
740
opt.conjugate_func(self)
741
742
if hasattr(self, '_real_part_'):
743
opt.real_part_func(self)
744
745
if hasattr(self, '_imag_part_'):
746
opt.imag_part_func(self)
747
748
if hasattr(self, '_derivative_'):
749
opt.derivative_func(self)
750
751
if hasattr(self, '_tderivative_'):
752
opt.do_not_apply_chain_rule()
753
opt.derivative_func(self)
754
755
if hasattr(self, '_power_'):
756
opt.power_func(self)
757
758
if hasattr(self, '_series_'):
759
opt.series_func(self)
760
761
# overriding print functions is not supported
762
763
if self._latex_name:
764
opt.latex_name(self._latex_name)
765
766
g_foptions_assign(g_registered_functions().index(self._serial), opt)
767
768
769
cdef class BuiltinFunction(Function):
770
"""
771
This is the base class for symbolic functions defined in Sage.
772
773
If a function is provided by the Sage library, we don't need to pickle
774
the custom methods, since we can just initialize the same library function
775
again. This allows us to use Cython for custom methods.
776
777
We assume that each subclass of this class will define one symbolic
778
function. Make sure you use subclasses and not just call the initializer
779
of this class.
780
"""
781
def __init__(self, name, nargs=1, latex_name=None, conversions=None,
782
evalf_params_first=True, alt_name=None):
783
"""
784
TESTS::
785
786
sage: from sage.functions.trig import Function_cot
787
sage: c = Function_cot() # indirect doctest
788
sage: c(pi/2)
789
0
790
"""
791
Function.__init__(self, name, nargs, latex_name, conversions,
792
evalf_params_first, alt_name = alt_name)
793
794
def __call__(self, *args, bint coerce=True, bint hold=False,
795
bint dont_call_method_on_arg=False):
796
r"""
797
Evaluate this function on the given arguments and return the result.
798
799
EXAMPLES::
800
801
sage: exp(5)
802
e^5
803
sage: gamma(15)
804
87178291200
805
806
TESTS::
807
808
sage: from sage.symbolic.function import BuiltinFunction
809
sage: class A:
810
....: def foo(self):
811
....: return 'foo'
812
sage: foo = BuiltinFunction(name='foo')
813
sage: foo(A())
814
'foo'
815
sage: bar = BuiltinFunction(name='bar', alt_name='foo')
816
sage: bar(A())
817
'foo'
818
"""
819
# if there is only one argument, and the argument has an attribute
820
# with the same name as this function, try to call it to get the result
821
# The argument dont_call_method_on_arg is used to prevent infinite loops
822
# when .exp(), .log(), etc. methods call this symbolic function on
823
# themselves
824
if len(args) == 1 and not hold and not dont_call_method_on_arg:
825
arg = args[0]
826
method = getattr(arg, self._name, None)
827
if method is not None:
828
return method()
829
elif self._alt_name is not None:
830
method = getattr(arg, self._alt_name, None)
831
if method is not None:
832
return method()
833
834
res = super(BuiltinFunction, self).__call__(
835
*args, coerce=coerce, hold=hold)
836
837
# we want to convert the result to the original parent if the input
838
# is not exact, so we store the parent here
839
org_parent = parent_c(args[0])
840
841
# convert the result back to the original parent previously stored
842
# otherwise we end up with
843
# sage: arctan(RR(1))
844
# 1/4*pi
845
# which is surprising, to say the least...
846
if org_parent is not SR and \
847
(org_parent is float or org_parent is complex or \
848
(PY_TYPE_CHECK(org_parent, Parent) and \
849
not org_parent.is_exact())):
850
try:
851
return org_parent(res)
852
except (TypeError, ValueError):
853
pass
854
855
# conversion to the original parent failed
856
# we try if it works with the corresponding complex domain
857
if org_parent is float:
858
try:
859
return complex(res)
860
except (TypeError, ValueError):
861
pass
862
elif hasattr(org_parent, 'complex_field'):
863
try:
864
return org_parent.complex_field()(res)
865
except (TypeError, ValueError):
866
pass
867
868
return res
869
870
cdef _is_registered(self):
871
"""
872
TESTS:
873
874
Check if :trac:`13586` is fixed::
875
876
sage: from sage.symbolic.function import BuiltinFunction
877
sage: class AFunction(BuiltinFunction):
878
....: def __init__(self, name, exp=1):
879
....: self.exponent=exp
880
....: BuiltinFunction.__init__(self, name, nargs=1)
881
....: def _eval_(self, arg):
882
....: return arg**self.exponent
883
sage: p2 = AFunction('p2', 2)
884
sage: p2(x)
885
x^2
886
sage: p3 = AFunction('p3', 3)
887
sage: p3(x)
888
x^3
889
"""
890
# check if already defined
891
cdef int serial = -1
892
893
# search ginac registry for name and nargs
894
try:
895
serial = find_function(self._name, self._nargs)
896
except ValueError, err:
897
pass
898
899
# if match, get operator from function table
900
global sfunction_serial_dict
901
if serial != -1 and sfunction_serial_dict.has_key(self._name) and \
902
sfunction_serial_dict[self._name].__class__ == self.__class__:
903
# if the returned function is of the same type
904
self._serial = serial
905
return True
906
907
# search the function table to check if any of this type
908
for key, val in sfunction_serial_dict.iteritems():
909
if key == self._name and val.__class__ == self.__class__:
910
self._serial = key
911
return True
912
913
return False
914
915
def __reduce__(self):
916
"""
917
EXAMPLES::
918
919
sage: cot.__reduce__()
920
(<class 'sage.functions.trig.Function_cot'>, ())
921
922
sage: f = loads(dumps(cot)) #indirect doctest
923
sage: f(pi/2)
924
0
925
"""
926
return self.__class__, tuple()
927
928
# this is required to read old pickles of erf, elliptic_ec, etc.
929
def __setstate__(self, state):
930
"""
931
EXAMPLES::
932
933
sage: cot.__setstate__([1,0])
934
Traceback (most recent call last):
935
...
936
ValueError: cannot read pickle
937
sage: cot.__setstate__([0]) #don't try this at home
938
"""
939
if state[0] == 0:
940
# old pickle data
941
# we call __init__ since Python only allocates the class and does
942
# not call __init__ before passing the pickled state to __setstate__
943
self.__init__()
944
else:
945
# we should never end up here
946
raise ValueError, "cannot read pickle"
947
948
949
cdef class SymbolicFunction(Function):
950
"""
951
This is the basis for user defined symbolic functions. We try to pickle or
952
hash the custom methods, so subclasses must be defined in Python not Cython.
953
"""
954
def __init__(self, name, nargs=0, latex_name=None, conversions=None,
955
evalf_params_first=True):
956
"""
957
EXAMPLES::
958
959
sage: from sage.symbolic.function import SymbolicFunction
960
sage: class my_function(SymbolicFunction):
961
....: def __init__(self):
962
....: SymbolicFunction.__init__(self, 'foo', nargs=2)
963
....: def _evalf_(self, x, y, parent=None):
964
....: return x*y*2r
965
....: def _conjugate_(self, x, y):
966
....: return x
967
sage: foo = my_function()
968
sage: foo
969
foo
970
sage: foo(2,3)
971
foo(2, 3)
972
sage: foo(2,3).n()
973
12.0000000000000
974
sage: foo(2,3).conjugate()
975
2
976
"""
977
self.__hinit = False
978
Function.__init__(self, name, nargs, latex_name, conversions,
979
evalf_params_first)
980
981
982
cdef _is_registered(SymbolicFunction self):
983
# see if there is already an SFunction with the same state
984
cdef Function sfunc
985
cdef long myhash = self._hash_()
986
for sfunc in sfunction_serial_dict.itervalues():
987
if PY_TYPE_CHECK(sfunc, SymbolicFunction) and \
988
myhash == (<SymbolicFunction>sfunc)._hash_():
989
# found one, set self._serial to be a copy
990
self._serial = sfunc._serial
991
return True
992
993
return False
994
995
# cache the hash value of this function
996
# this is used very often while unpickling to see if there is already
997
# a function with the same properties
998
cdef long _hash_(self) except -1:
999
if not self.__hinit:
1000
# create a string representation of this SFunction
1001
slist = [self._nargs, self._name, str(self._latex_name),
1002
self._evalf_params_first]
1003
for fname in sfunctions_funcs:
1004
real_fname = '_%s_'%fname
1005
if hasattr(self, '%s'%real_fname):
1006
slist.append(hash(getattr(self, real_fname).func_code))
1007
else:
1008
slist.append(' ')
1009
self.__hcache = hash(tuple(slist))
1010
self.__hinit = True
1011
return self.__hcache
1012
1013
def __hash__(self):
1014
"""
1015
TESTS::
1016
1017
sage: foo = function("foo", nargs=2)
1018
sage: hash(foo) # random output
1019
-6859868030555295348
1020
1021
sage: def ev(self, x): return 2*x
1022
sage: foo = function("foo", nargs=2, eval_func = ev)
1023
sage: hash(foo) # random output
1024
-6859868030555295348
1025
"""
1026
return self._serial*self._hash_()
1027
1028
def __getstate__(self):
1029
"""
1030
Returns a tuple describing the state of this object for pickling.
1031
1032
Pickling SFunction objects is limited by the ability to pickle
1033
functions in python. We use sage.misc.fpickle.pickle_function for
1034
this purpose, which only works if there are no nested functions.
1035
1036
1037
This should return all information that will be required to unpickle
1038
the object. The functionality for unpickling is implemented in
1039
__setstate__().
1040
1041
In order to pickle SFunction objects, we return a tuple containing
1042
1043
* 0 - as pickle version number
1044
in case we decide to change the pickle format in the feature
1045
* name of this function
1046
* number of arguments
1047
* latex_name
1048
* a tuple containing attempts to pickle the following optional
1049
functions, in the order below
1050
* eval_f
1051
* evalf_f
1052
* conjugate_f
1053
* real_part_f
1054
* imag_part_f
1055
* derivative_f
1056
* power_f
1057
* series_f
1058
* print_f
1059
* print_latex_f
1060
1061
EXAMPLES::
1062
1063
sage: foo = function("foo", nargs=2)
1064
sage: foo.__getstate__()
1065
(2, 'foo', 2, None, {}, True, [None, None, None, None, None, None, None, None, None, None, None])
1066
sage: t = loads(dumps(foo))
1067
sage: t == foo
1068
True
1069
sage: var('x,y')
1070
(x, y)
1071
sage: t(x,y)
1072
foo(x, y)
1073
1074
sage: def ev(self, x,y): return 2*x
1075
sage: foo = function("foo", nargs=2, eval_func = ev)
1076
sage: foo.__getstate__()
1077
(2, 'foo', 2, None, {}, True, ["...", None, None, None, None, None, None, None, None, None, None])
1078
1079
sage: u = loads(dumps(foo))
1080
sage: u == foo
1081
True
1082
sage: t == u
1083
False
1084
sage: u(y,x)
1085
2*y
1086
1087
sage: def evalf_f(self, x, parent=None): return int(6)
1088
sage: foo = function("foo", nargs=1, evalf_func=evalf_f)
1089
sage: foo.__getstate__()
1090
(2, 'foo', 1, None, {}, True, [None, "...", None, None, None, None, None, None, None, None, None])
1091
1092
sage: v = loads(dumps(foo))
1093
sage: v == foo
1094
True
1095
sage: v == u
1096
False
1097
sage: foo(y).n()
1098
6
1099
sage: v(y).n()
1100
6
1101
1102
Test pickling expressions with symbolic functions::
1103
1104
sage: u = loads(dumps(foo(x)^2 + foo(y) + x^y)); u
1105
foo(x)^2 + x^y + foo(y)
1106
sage: u.subs(y=0)
1107
foo(x)^2 + foo(0) + 1
1108
sage: u.subs(y=0).n()
1109
43.0000000000000
1110
"""
1111
return (2, self._name, self._nargs, self._latex_name, self._conversions,
1112
self._evalf_params_first,
1113
map(pickle_wrapper, [getattr(self, '_%s_'%fname) \
1114
if hasattr(self, '_%s_'%fname) else None \
1115
for fname in sfunctions_funcs]))
1116
1117
def __setstate__(self, state):
1118
"""
1119
Initializes the state of the object from data saved in a pickle.
1120
1121
During unpickling __init__ methods of classes are not called, the saved
1122
data is passed to the class via this function instead.
1123
1124
TESTS::
1125
1126
sage: var('x,y')
1127
(x, y)
1128
sage: foo = function("foo", nargs=2)
1129
sage: bar = function("bar", nargs=1)
1130
sage: bar.__setstate__(foo.__getstate__())
1131
1132
::
1133
1134
sage: g = function('g', nargs=1, conjugate_func=lambda y,x: 2*x)
1135
sage: st = g.__getstate__()
1136
sage: f = function('f')
1137
sage: f(x)
1138
f(x)
1139
sage: f(x).conjugate() # no special conjugate method
1140
conjugate(f(x))
1141
sage: f.__setstate__(st)
1142
sage: f(x+1).conjugate() # now there is a special method
1143
2*x + 2
1144
1145
Note that the other direction doesn't work here, since foo._hash_()
1146
hash already been initialized.::
1147
1148
sage: bar
1149
foo
1150
sage: bar(x,y)
1151
foo(x, y)
1152
"""
1153
# check input
1154
if not ((state[0] == 1 and len(state) == 6) or \
1155
(state[0] == 2 and len(state) == 7)):
1156
raise ValueError, "unknown state information"
1157
1158
name = state[1]
1159
nargs = state[2]
1160
latex_name = state[3]
1161
conversions = state[4]
1162
1163
if state[0] == 1:
1164
evalf_params_first = True
1165
function_pickles = state[5]
1166
elif state[0] == 2:
1167
evalf_params_first = state[5]
1168
function_pickles = state[6]
1169
1170
for pickle, fname in zip(function_pickles, sfunctions_funcs):
1171
if pickle:
1172
real_fname = '_%s_'%fname
1173
setattr(self, real_fname, unpickle_function(pickle))
1174
1175
SymbolicFunction.__init__(self, name, nargs, latex_name,
1176
conversions, evalf_params_first)
1177
1178
1179
cdef class DeprecatedSFunction(SymbolicFunction):
1180
cdef dict __dict__
1181
def __init__(self, name, nargs=0, latex_name=None):
1182
"""
1183
EXAMPLES::
1184
1185
sage: from sage.symbolic.function import DeprecatedSFunction
1186
sage: foo = DeprecatedSFunction("foo", 2)
1187
sage: foo
1188
foo
1189
sage: foo(x,2)
1190
foo(x, 2)
1191
sage: foo(2)
1192
Traceback (most recent call last):
1193
...
1194
TypeError: Symbolic function foo takes exactly 2 arguments (1 given)
1195
"""
1196
self.__dict__ = {}
1197
SymbolicFunction.__init__(self, name, nargs, latex_name)
1198
1199
def __getattr__(self, attr):
1200
"""
1201
This method allows us to access attributes set by
1202
:meth:`__setattr__`.
1203
1204
EXAMPLES::
1205
1206
sage: from sage.symbolic.function import DeprecatedSFunction
1207
sage: foo = DeprecatedSFunction("foo", 2)
1208
sage: foo.bar = 4
1209
sage: foo.bar
1210
4
1211
"""
1212
try:
1213
return self.__dict__[attr]
1214
except KeyError:
1215
raise AttributeError, attr
1216
1217
def __setattr__(self, attr, value):
1218
"""
1219
This method allows us to store arbitrary Python attributes
1220
on symbolic functions which is normally not possible with
1221
Cython extension types.
1222
1223
EXAMPLES::
1224
1225
sage: from sage.symbolic.function import DeprecatedSFunction
1226
sage: foo = DeprecatedSFunction("foo", 2)
1227
sage: foo.bar = 4
1228
sage: foo.bar
1229
4
1230
"""
1231
self.__dict__[attr] = value
1232
1233
def __reduce__(self):
1234
"""
1235
EXAMPLES::
1236
1237
sage: from sage.symbolic.function import DeprecatedSFunction
1238
sage: foo = DeprecatedSFunction("foo", 2)
1239
sage: foo.__reduce__()
1240
(<function unpickle_function at ...>, ('foo', 2, None, {}, True, [None, None, None, None, None, None, None, None, None, None, None]))
1241
"""
1242
from sage.symbolic.function_factory import unpickle_function
1243
state = self.__getstate__()
1244
name = state[1]
1245
nargs = state[2]
1246
latex_name = state[3]
1247
conversions = state[4]
1248
evalf_params_first = state[5]
1249
pickled_functions = state[6]
1250
return (unpickle_function, (name, nargs, latex_name, conversions,
1251
evalf_params_first, pickled_functions))
1252
1253
def __setstate__(self, state):
1254
"""
1255
EXAMPLES::
1256
1257
sage: from sage.symbolic.function import DeprecatedSFunction
1258
sage: foo = DeprecatedSFunction("foo", 2)
1259
sage: foo.__setstate__([0, 'bar', 1, '\\bar', [None]*10])
1260
sage: foo
1261
bar
1262
sage: foo(x)
1263
bar(x)
1264
sage: latex(foo(x))
1265
\bar\left(x\right)
1266
"""
1267
name = state[1]
1268
nargs = state[2]
1269
latex_name = state[3]
1270
self.__dict__ = {}
1271
for pickle, fname in zip(state[4], sfunctions_funcs):
1272
if pickle:
1273
if fname == 'evalf':
1274
from sage.symbolic.function_factory import \
1275
deprecated_custom_evalf_wrapper
1276
setattr(self, '_evalf_',
1277
deprecated_custom_evalf_wrapper(
1278
unpickle_function(pickle)))
1279
continue
1280
real_fname = '_%s_'%fname
1281
setattr(self, real_fname, unpickle_function(pickle))
1282
1283
SymbolicFunction.__init__(self, name, nargs, latex_name, None)
1284
1285
SFunction = DeprecatedSFunction
1286
PrimitiveFunction = DeprecatedSFunction
1287
1288
1289
def get_sfunction_from_serial(serial):
1290
"""
1291
Returns an already created SFunction given the serial. These are
1292
stored in the dictionary
1293
`sage.symbolic.function.sfunction_serial_dict`.
1294
1295
EXAMPLES::
1296
1297
sage: from sage.symbolic.function import get_sfunction_from_serial
1298
sage: get_sfunction_from_serial(65) #random
1299
f
1300
"""
1301
global sfunction_serial_dict
1302
return sfunction_serial_dict.get(serial)
1303
1304
def pickle_wrapper(f):
1305
"""
1306
Returns a pickled version of the function f if f is not None;
1307
otherwise, it returns None. This is a wrapper around
1308
:func:`pickle_function`.
1309
1310
EXAMPLES::
1311
1312
sage: from sage.symbolic.function import pickle_wrapper
1313
sage: def f(x): return x*x
1314
sage: pickle_wrapper(f)
1315
"csage...."
1316
sage: pickle_wrapper(None) is None
1317
True
1318
"""
1319
if f is None:
1320
return None
1321
return pickle_function(f)
1322
1323
def unpickle_wrapper(p):
1324
"""
1325
Returns a unpickled version of the function defined by *p* if *p*
1326
is not None; otherwise, it returns None. This is a wrapper around
1327
:func:`unpickle_function`.
1328
1329
EXAMPLES::
1330
1331
sage: from sage.symbolic.function import pickle_wrapper, unpickle_wrapper
1332
sage: def f(x): return x*x
1333
sage: s = pickle_wrapper(f)
1334
sage: g = unpickle_wrapper(s)
1335
sage: g(2)
1336
4
1337
sage: unpickle_wrapper(None) is None
1338
True
1339
"""
1340
if p is None:
1341
return None
1342
return unpickle_function(p)
1343
1344
def is_inexact(x):
1345
"""
1346
Returns True if the argument is an inexact object.
1347
1348
TESTS::
1349
1350
sage: from sage.symbolic.function import is_inexact
1351
sage: is_inexact(5)
1352
False
1353
sage: is_inexact(5.)
1354
True
1355
sage: is_inexact(pi)
1356
True
1357
sage: is_inexact(5r)
1358
False
1359
sage: is_inexact(5.4r)
1360
True
1361
"""
1362
if isinstance(x, (float, complex)):
1363
return True
1364
if isinstance(x, Element):
1365
return not (<Element>x)._parent.is_exact()
1366
return False
1367
1368