Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/misc/derivative.pyx
4056 views
1
#*****************************************************************************
2
# Copyright (C) 2008 William Stein <[email protected]>
3
#
4
# Distributed under the terms of the GNU General Public License (GPL)
5
#
6
# This code is distributed in the hope that it will be useful,
7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
8
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9
# General Public License for more details.
10
#
11
# The full text of the GPL is available at:
12
#
13
# http://www.gnu.org/licenses/
14
#*****************************************************************************
15
16
r"""
17
Utility functions for making derivative() behave uniformly across Sage.
18
19
To use these functions:
20
21
(1) attach the following method to your class:
22
23
def _derivative(self, var=None):
24
[ should differentiate wrt the single variable var and return
25
result; var==None means attempt to differentiate wrt a `default'
26
variable. ]
27
28
(2) from sage.misc.derivative import multi_derivative
29
30
(3) add the following method to your class:
31
32
def derivative(self, *args):
33
return multi_derivative(self, args)
34
35
Then your object will support the standard parameter format for derivative().
36
For example:
37
38
F.derivative():
39
diff wrt. default variable (calls F._derivative(None))
40
41
F.derivative(3):
42
diff three times wrt default variable (calls F._derivative(None) three times)
43
44
F.derivative(x):
45
diff wrt x (calls F._derivative(x))
46
47
F.derivative(1, x, z, 3, y, 2, 2):
48
diff once wrt default variable, then once wrt x, then three times wrt z,
49
then twice wrt y, then twice wrt default variable.
50
51
F.derivative([None, x, z, z, z, y, y, None, None]):
52
identical to previous example
53
54
For the precise specification see documentation for derivative_parse().
55
56
AUTHORS:
57
-- David Harvey (2008-02)
58
59
TODO:
60
-- This stuff probably belongs somewhere like sage/misc/misc_c.pyx.
61
The only reason it's in its own file here is because of some circular cimport
62
problems (can't cimport Integer to sage/misc/misc_c.pyx). For further
63
discussion see
64
http://codespeak.net/pipermail/cython-dev/2008-February/000057.html
65
66
"""
67
68
from sage.rings.integer cimport Integer
69
70
71
def derivative_parse(args):
72
r"""
73
Translates a sequence consisting of `variables' and iteration counts into
74
a single sequence of variables.
75
76
INPUT:
77
args -- any iterable, interpreted as a sequence of `variables' and
78
iteration counts. An iteration count is any integer type (python int
79
or Sage Integer). Iteration counts must be non-negative. Any object
80
which is not an integer is assumed to be a variable.
81
82
OUTPUT:
83
A sequence, the `expanded' version of the input, defined as follows.
84
Read the input from left to right. If you encounter a variable V
85
followed by an iteration count N, then output N copies of V. If V
86
is not followed by an iteration count, output a single copy of V.
87
If you encounter an iteration count N (not attached to a preceding
88
variable), then output N copies of None.
89
90
Special case: if input is empty, output [None] (i.e. ``differentiate
91
once with respect to the default variable'').
92
93
Special case: if the input is a 1-tuple containing a single list,
94
then the return value is simply that list.
95
96
EXAMPLES:
97
sage: x = var("x")
98
sage: y = var("y")
99
sage: from sage.misc.derivative import derivative_parse
100
101
Differentiate twice with respect to x, then once with respect to y,
102
then once with respect to x:
103
sage: derivative_parse([x, 2, y, x])
104
[x, x, y, x]
105
106
Differentiate twice with respect to x, then twice with respect to
107
the `default variable':
108
sage: derivative_parse([x, 2, 2])
109
[x, x, None, None]
110
111
Special case with empty input list:
112
sage: derivative_parse([])
113
[None]
114
115
sage: derivative_parse([-1])
116
Traceback (most recent call last):
117
...
118
ValueError: derivative counts must be non-negative
119
120
Special case with single list argument provided:
121
sage: derivative_parse(([x, y], ))
122
[x, y]
123
124
If only the count is supplied:
125
sage: derivative_parse([0])
126
[]
127
sage: derivative_parse([1])
128
[None]
129
sage: derivative_parse([2])
130
[None, None]
131
sage: derivative_parse([int(2)])
132
[None, None]
133
134
Various other cases:
135
sage: derivative_parse([x])
136
[x]
137
sage: derivative_parse([x, x])
138
[x, x]
139
sage: derivative_parse([x, 2])
140
[x, x]
141
sage: derivative_parse([x, 0])
142
[]
143
sage: derivative_parse([x, y, x, 2, 2, y])
144
[x, y, x, x, None, None, y]
145
146
"""
147
if not args:
148
return [None]
149
if len(args) == 1 and isinstance(args[0], list):
150
return args[0]
151
152
output = []
153
cdef bint got_var = 0 # have a variable saved up from last loop?
154
cdef int count, i
155
156
for arg in args:
157
if isinstance(arg, (int, Integer)):
158
# process iteration count
159
count = int(arg)
160
if count < 0:
161
raise ValueError, "derivative counts must be non-negative"
162
if not got_var:
163
var = None
164
for i from 0 <= i < count:
165
output.append(var)
166
got_var = 0
167
else:
168
# process variable
169
if got_var:
170
output.append(var)
171
got_var = 1
172
var = arg
173
174
if got_var:
175
output.append(var)
176
177
return output
178
179
180
181
def multi_derivative(F, args):
182
r"""
183
Calls F._derivative(var) for a sequence of variables specified by args.
184
185
INPUT:
186
F -- any object with a _derivative(var) method.
187
args -- any tuple that can be processed by derivative_parse().
188
189
EXAMPLES:
190
sage: from sage.misc.derivative import multi_derivative
191
sage: R.<x, y, z> = PolynomialRing(QQ)
192
sage: f = x^3 * y^4 * z^5
193
sage: multi_derivative(f, (x,)) # like f.derivative(x)
194
3*x^2*y^4*z^5
195
sage: multi_derivative(f, (x, y, x)) # like f.derivative(x, y, x)
196
24*x*y^3*z^5
197
sage: multi_derivative(f, ([x, y, x],)) # like f.derivative([x, y, x])
198
24*x*y^3*z^5
199
sage: multi_derivative(f, (x, 2)) # like f.derivative(x, 2)
200
6*x*y^4*z^5
201
202
sage: R.<x> = PolynomialRing(QQ)
203
sage: f = x^4 + x^2 + 1
204
sage: multi_derivative(f, []) # like f.derivative()
205
4*x^3 + 2*x
206
sage: multi_derivative(f, [[]]) # like f.derivative([])
207
x^4 + x^2 + 1
208
sage: multi_derivative(f, [x]) # like f.derivative(x)
209
4*x^3 + 2*x
210
"""
211
if not args:
212
# fast version where no arguments supplied
213
return F._derivative()
214
215
for arg in derivative_parse(args):
216
F = F._derivative(arg)
217
return F
218
219
220