Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/symbolic/callable.py
4077 views
1
"""
2
Callable Symbolic Expressions
3
4
EXAMPLES::
5
6
When you do arithmetic with
7
8
sage: f(x, y, z) = sin(x+y+z)
9
sage: g(x, y) = y + 2*x
10
sage: f + g
11
(x, y, z) |--> 2*x + y + sin(x + y + z)
12
13
::
14
15
sage: f(x, y, z) = sin(x+y+z)
16
sage: g(w, t) = cos(w - t)
17
sage: f + g
18
(t, w, x, y, z) |--> sin(x + y + z) + cos(-t + w)
19
20
::
21
22
sage: f(x, y, t) = y*(x^2-t)
23
sage: g(x, y, w) = x + y - cos(w)
24
sage: f*g
25
(x, y, t, w) |--> (x^2 - t)*(x + y - cos(w))*y
26
27
::
28
29
sage: f(x,y, t) = x+y
30
sage: g(x, y, w) = w + t
31
sage: f + g
32
(x, y, t, w) |--> t + w + x + y
33
34
TESTS:
35
36
The arguments in the definition must be symbolic variables #10747::
37
38
sage: f(1)=2
39
Traceback (most recent call last):
40
...
41
SyntaxError: can't assign to function call
42
43
sage: f(x,1)=2
44
Traceback (most recent call last):
45
...
46
SyntaxError: can't assign to function call
47
48
sage: f(1,2)=3
49
Traceback (most recent call last):
50
...
51
SyntaxError: can't assign to function call
52
53
sage: f(1,2)=x
54
Traceback (most recent call last):
55
...
56
SyntaxError: can't assign to function call
57
58
sage: f(x,2)=x
59
Traceback (most recent call last):
60
...
61
SyntaxError: can't assign to function call
62
"""
63
64
from sage.symbolic.ring import SymbolicRing, SR, ParentWithBase
65
from sage.categories.pushout import ConstructionFunctor
66
67
#########################################################################################
68
# Callable functions
69
#########################################################################################
70
def is_CallableSymbolicExpressionRing(x):
71
"""
72
Return True if x is a callable symbolic expression ring.
73
74
INPUT:
75
76
- ``x`` - object
77
78
OUTPUT: bool
79
80
EXAMPLES::
81
82
sage: from sage.symbolic.callable import is_CallableSymbolicExpressionRing
83
sage: is_CallableSymbolicExpressionRing(QQ)
84
False
85
sage: var('x,y,z')
86
(x, y, z)
87
sage: is_CallableSymbolicExpressionRing(CallableSymbolicExpressionRing((x,y,z)))
88
True
89
"""
90
return isinstance(x, CallableSymbolicExpressionRing_class)
91
92
def is_CallableSymbolicExpression(x):
93
r"""
94
Returns true if ``x`` is a callable symbolic
95
expression.
96
97
EXAMPLES::
98
99
sage: from sage.symbolic.callable import is_CallableSymbolicExpression
100
sage: var('a x y z')
101
(a, x, y, z)
102
sage: f(x,y) = a + 2*x + 3*y + z
103
sage: is_CallableSymbolicExpression(f)
104
True
105
sage: is_CallableSymbolicExpression(a+2*x)
106
False
107
sage: def foo(n): return n^2
108
...
109
sage: is_CallableSymbolicExpression(foo)
110
False
111
"""
112
from sage.symbolic.expression import is_Expression
113
return is_Expression(x) and isinstance(x.parent(), CallableSymbolicExpressionRing_class)
114
115
class CallableSymbolicExpressionFunctor(ConstructionFunctor):
116
def __init__(self, arguments):
117
"""
118
A functor which produces a CallableSymbolicExpressionRing from
119
the SymbolicRing.
120
121
EXAMPLES::
122
123
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
124
sage: x,y = var('x,y')
125
sage: f = CallableSymbolicExpressionFunctor((x,y)); f
126
CallableSymbolicExpressionFunctor(x, y)
127
sage: f(SR)
128
Callable function ring with arguments (x, y)
129
130
sage: loads(dumps(f))
131
CallableSymbolicExpressionFunctor(x, y)
132
"""
133
self._arguments = arguments
134
from sage.categories.all import Rings
135
self.rank = 3
136
ConstructionFunctor.__init__(self, Rings(), Rings())
137
138
def __repr__(self):
139
"""
140
EXAMPLES::
141
142
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
143
sage: x,y = var('x,y')
144
sage: CallableSymbolicExpressionFunctor((x,y))
145
CallableSymbolicExpressionFunctor(x, y)
146
"""
147
return "CallableSymbolicExpressionFunctor%s"%repr(self.arguments())
148
149
def merge(self, other):
150
"""
151
EXAMPLES::
152
153
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
154
sage: x,y = var('x,y')
155
sage: a = CallableSymbolicExpressionFunctor((x,))
156
sage: b = CallableSymbolicExpressionFunctor((y,))
157
sage: a.merge(b)
158
CallableSymbolicExpressionFunctor(x, y)
159
"""
160
arguments = self.unify_arguments(other)
161
return CallableSymbolicExpressionFunctor(arguments)
162
163
def __call__(self, R):
164
"""
165
EXAMPLES::
166
167
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
168
sage: x,y = var('x,y')
169
sage: a = CallableSymbolicExpressionFunctor((x,y))
170
sage: a(SR)
171
Callable function ring with arguments (x, y)
172
"""
173
if R is not SR:
174
raise ValueError, "Can only make callable symbolic expression rings from the Symbolic Ring"
175
return CallableSymbolicExpressionRing(self.arguments())
176
177
def arguments(self):
178
"""
179
EXAMPLES::
180
181
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
182
sage: x,y = var('x,y')
183
sage: a = CallableSymbolicExpressionFunctor((x,y))
184
sage: a.arguments()
185
(x, y)
186
"""
187
return self._arguments
188
189
def unify_arguments(self, x):
190
r"""
191
Takes the variable list from another
192
``CallableSymbolicExpression`` object and compares it with the
193
current ``CallableSymbolicExpression`` object's variable list,
194
combining them according to the following rules:
195
196
Let ``a`` be ``self``'s variable list, let ``b`` be ``y``'s
197
variable list.
198
199
#. If ``a == b``, then the variable lists are
200
identical, so return that variable list.
201
202
#. If ``a`` `\neq` ``b``, then check if the first `n` items in
203
``a`` are the first `n` items in ``b``, or vice versa. If
204
so, return a list with these `n` items, followed by the
205
remaining items in ``a`` and ``b`` sorted together in
206
alphabetical order.
207
208
209
.. note::
210
211
When used for arithmetic between
212
``CallableSymbolicExpression``s, these rules ensure that
213
the set of ``CallableSymbolicExpression``s will have
214
certain properties. In particular, it ensures that the set
215
is a *commutative* ring, i.e., the order of the input
216
variables is the same no matter in which order arithmetic
217
is done.
218
219
INPUT:
220
221
- ``x`` - A CallableSymbolicExpression
222
223
OUTPUT: A tuple of variables.
224
225
EXAMPLES::
226
227
sage: from sage.symbolic.callable import CallableSymbolicExpressionFunctor
228
sage: x,y = var('x,y')
229
sage: a = CallableSymbolicExpressionFunctor((x,))
230
sage: b = CallableSymbolicExpressionFunctor((y,))
231
sage: a.unify_arguments(b)
232
(x, y)
233
234
AUTHORS:
235
236
- Bobby Moretti: thanks to William Stein for the rules
237
"""
238
from sage.calculus.calculus import var_cmp
239
a = self.arguments()
240
b = x.arguments()
241
242
# Rule #1
243
if [str(x) for x in a] == [str(x) for x in b]:
244
return a
245
246
# Rule #2
247
new_list = []
248
done = False
249
i = 0
250
while not done and i < min(len(a), len(b)):
251
if var_cmp(a[i], b[i]) == 0:
252
new_list.append(a[i])
253
i += 1
254
else:
255
done = True
256
257
temp = set([])
258
# Sorting remaining variables.
259
for j in range(i, len(a)):
260
if not a[j] in temp:
261
temp.add(a[j])
262
263
for j in range(i, len(b)):
264
if not b[j] in temp:
265
temp.add(b[j])
266
267
temp = list(temp)
268
temp.sort(var_cmp)
269
new_list.extend(temp)
270
return tuple(new_list)
271
272
273
class CallableSymbolicExpressionRing_class(SymbolicRing):
274
def __init__(self, arguments):
275
"""
276
EXAMPLES:
277
278
We verify that coercion works in the case where x is not an
279
instance of SymbolicExpression, but its parent is still the
280
SymbolicRing::
281
282
sage: f(x) = 1
283
sage: f*e
284
x |--> e
285
"""
286
self._arguments = arguments
287
ParentWithBase.__init__(self, SR)
288
self._populate_coercion_lists_(coerce_list=[SR])
289
290
def __hash__(self):
291
"""
292
EXAMPLES::
293
294
sage: f(x,y) = x + y
295
sage: hash(f.parent()) #random
296
-8878119762643067638
297
"""
298
return hash((self.__class__, self._arguments))
299
300
def __cmp__(self, other):
301
"""
302
EXAMPLES::
303
304
sage: f(x) = x+1
305
sage: g(y) = y+1
306
sage: h(x) = x^2
307
sage: f.parent() == g.parent()
308
False
309
sage: f.parent() == h.parent()
310
True
311
"""
312
if self.__class__ != other.__class__:
313
return cmp(self.__class__, other.__class__)
314
else:
315
return cmp(self._arguments, other._arguments)
316
317
def _coerce_map_from_(self, R):
318
"""
319
EXAMPLES::
320
321
sage: f(x,y) = x^2 + y
322
sage: g(x,y,z) = x + y + z
323
sage: f.parent().has_coerce_map_from(g.parent())
324
False
325
sage: g.parent().has_coerce_map_from(f.parent())
326
True
327
"""
328
if is_CallableSymbolicExpressionRing(R):
329
args = self.arguments()
330
if all(a in args for a in R.arguments()):
331
return True
332
else:
333
return False
334
return SymbolicRing._coerce_map_from_(self, R)
335
336
def construction(self):
337
"""
338
EXAMPLES::
339
340
sage: f(x,y) = x^2 + y
341
sage: f.parent().construction()
342
(CallableSymbolicExpressionFunctor(x, y), Symbolic Ring)
343
"""
344
return (CallableSymbolicExpressionFunctor(self.arguments()), SR)
345
346
def _element_constructor_(self, x):
347
"""
348
TESTS::
349
350
sage: f(x) = x+1; g(y) = y+1
351
sage: f.parent()(g)
352
x |--> y + 1
353
sage: g.parent()(f)
354
y |--> x + 1
355
sage: f(x) = x+2*y; g(y) = y+3*x
356
sage: f.parent()(g)
357
x |--> 3*x + y
358
sage: g.parent()(f)
359
y |--> x + 2*y
360
"""
361
return SymbolicRing._element_constructor_(self, x)
362
363
def _repr_(self):
364
"""
365
String representation of ring of callable symbolic expressions.
366
367
EXAMPLES::
368
369
sage: R = CallableSymbolicExpressionRing(var('x,y,theta'))
370
sage: R._repr_()
371
'Callable function ring with arguments (x, y, theta)'
372
"""
373
return "Callable function ring with arguments %s"%(self._arguments,)
374
375
def arguments(self):
376
r"""
377
Returns the arguments of ``self``. The order that the
378
variables appear in ``self.arguments()`` is the order that
379
is used in evaluating the elements of ``self``.
380
381
EXAMPLES::
382
383
sage: x,y = var('x,y')
384
sage: f(x,y) = 2*x+y
385
sage: f.parent().arguments()
386
(x, y)
387
sage: f(y,x) = 2*x+y
388
sage: f.parent().arguments()
389
(y, x)
390
"""
391
return self._arguments
392
393
args = arguments
394
395
def _repr_element_(self, x):
396
"""
397
Returns the string representation of the Expression x.
398
399
EXAMPLES::
400
401
sage: f(y,x) = x + y
402
sage: f
403
(y, x) |--> x + y
404
sage: f.parent()
405
Callable function ring with arguments (y, x)
406
407
"""
408
args = self.arguments()
409
repr_x = SymbolicRing._repr_element_(self, x)
410
if len(args) == 1:
411
return "%s |--> %s" % (args[0], repr_x)
412
else:
413
args = ", ".join(map(str, args))
414
return "(%s) |--> %s" % (args, repr_x)
415
416
def _latex_element_(self, x):
417
r"""
418
Finds the LaTeX representation of this expression.
419
420
EXAMPLES::
421
422
sage: f(A, t, omega, psi) = A*cos(omega*t - psi)
423
sage: f._latex_()
424
'\\left( A, t, \\omega, \\psi \\right) \\ {\\mapsto} \\ A \\cos\\left(\\omega t - \\psi\\right)'
425
426
sage: f(mu) = mu^3
427
sage: f._latex_()
428
'\\mu \\ {\\mapsto}\\ \\mu^{3}'
429
"""
430
from sage.misc.latex import latex
431
args = self.args()
432
args = [latex(arg) for arg in args]
433
latex_x = SymbolicRing._latex_element_(self, x)
434
if len(args) == 1:
435
return r"%s \ {\mapsto}\ %s" % (args[0], latex_x)
436
else:
437
vars = ", ".join(args)
438
# the weird TeX is to workaround an apparent JsMath bug
439
return r"\left( %s \right) \ {\mapsto} \ %s" % (vars, latex_x)
440
441
def _call_element_(self, _the_element, *args, **kwds):
442
"""
443
Calling a callable symbolic expression returns a symbolic expression
444
with the appropriate arguments substituted.
445
446
EXAMPLES::
447
448
sage: var('a, x, y, z')
449
(a, x, y, z)
450
sage: f(x,y) = a + 2*x + 3*y + z
451
sage: f
452
(x, y) |--> a + 2*x + 3*y + z
453
sage: f(1,2)
454
a + z + 8
455
sage: f(y=2, a=-1)
456
2*x + z + 5
457
458
Note that keyword arguments will override the regular arguments.
459
::
460
461
462
sage: f.arguments()
463
(x, y)
464
sage: f(1,2)
465
a + z + 8
466
sage: f(10,2)
467
a + z + 26
468
sage: f(10,2,x=1)
469
a + z + 8
470
sage: f(z=100)
471
a + 2*x + 3*y + 100
472
"""
473
if any([type(arg).__module__ == 'numpy' and type(arg).__name__ == "ndarray" for arg in args]): # avoid importing
474
raise NotImplementedError("Numpy arrays are not supported as arguments for symbolic expressions")
475
476
d = dict(zip(map(repr, self.arguments()), args))
477
d.update(kwds)
478
return SR(_the_element.substitute(**d))
479
480
481
482
from sage.structure.factory import UniqueFactory
483
class CallableSymbolicExpressionRingFactory(UniqueFactory):
484
def create_key(self, args, check=True):
485
"""
486
EXAMPLES::
487
488
sage: x,y = var('x,y')
489
sage: CallableSymbolicExpressionRing.create_key((x,y))
490
(x, y)
491
"""
492
if check:
493
from sage.symbolic.ring import is_SymbolicVariable
494
if len(args) == 1 and isinstance(args[0], (list, tuple)):
495
args, = args
496
for arg in args:
497
if not is_SymbolicVariable(arg):
498
raise TypeError, "Must construct a function with a tuple (or list) of variables."
499
args = tuple(args)
500
return args
501
502
def create_object(self, version, key, **extra_args):
503
"""
504
Returns a CallableSymbolicExpressionRing given a version and a
505
key.
506
507
EXAMPLES::
508
509
sage: x,y = var('x,y')
510
sage: CallableSymbolicExpressionRing.create_object(0, (x, y))
511
Callable function ring with arguments (x, y)
512
"""
513
return CallableSymbolicExpressionRing_class(key)
514
515
CallableSymbolicExpressionRing = CallableSymbolicExpressionRingFactory('sage.symbolic.callable.CallableSymbolicExpressionRing')
516
517
518