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