Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

#***************************************************************************** 

# Copyright (C) 2008 William Stein <wstein@gmail.com> 

# 

# Distributed under the terms of the GNU General Public License (GPL) 

# 

# This code is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 

# General Public License for more details. 

# 

# The full text of the GPL is available at: 

# 

# http://www.gnu.org/licenses/ 

#***************************************************************************** 

  

r""" 

Utility functions for making derivative() behave uniformly across Sage. 

  

To use these functions: 

  

1. attach the following method to your class:: 

  

def _derivative(self, var=None): 

[ should differentiate wrt the single variable var and return 

result; var==None means attempt to differentiate wrt a 'default' 

variable. ] 

  

2. from sage.misc.derivative import multi_derivative 

  

3. add the following method to your class:: 

  

def derivative(self, *args): 

return multi_derivative(self, args) 

  

Then your object will support the standard parameter format for derivative(). 

For example:: 

  

F.derivative(): 

diff wrt. default variable (calls F._derivative(None)) 

  

F.derivative(3): 

diff three times wrt default variable (calls F._derivative(None) three times) 

  

F.derivative(x): 

diff wrt x (calls F._derivative(x)) 

  

F.derivative(1, x, z, 3, y, 2, 2): 

diff once wrt default variable, then once wrt x, then three times wrt z, 

then twice wrt y, then twice wrt default variable. 

  

F.derivative([None, x, z, z, z, y, y, None, None]): 

identical to previous example 

  

For the precise specification see documentation for derivative_parse(). 

  

AUTHORS: 

  

- David Harvey (2008-02) 

  

""" 

  

from sage.rings.integer cimport Integer 

  

  

def derivative_parse(args): 

r""" 

Translates a sequence consisting of 'variables' and iteration counts into 

a single sequence of variables. 

  

INPUT: 

  

args -- any iterable, interpreted as a sequence of 'variables' and 

iteration counts. An iteration count is any integer type (python int 

or Sage Integer). Iteration counts must be non-negative. Any object 

which is not an integer is assumed to be a variable. 

  

OUTPUT: 

  

A sequence, the 'expanded' version of the input, defined as follows. 

Read the input from left to right. If you encounter a variable V 

followed by an iteration count N, then output N copies of V. If V 

is not followed by an iteration count, output a single copy of V. 

If you encounter an iteration count N (not attached to a preceding 

variable), then output N copies of None. 

  

Special case: if input is empty, output [None] (i.e. "differentiate 

once with respect to the default variable"). 

  

Special case: if the input is a 1-tuple containing a single list, 

then the return value is simply that list. 

  

EXAMPLES:: 

  

sage: x = var("x") 

sage: y = var("y") 

sage: from sage.misc.derivative import derivative_parse 

  

Differentiate twice with respect to x, then once with respect to y, 

then once with respect to x:: 

  

sage: derivative_parse([x, 2, y, x]) 

[x, x, y, x] 

  

Differentiate twice with respect to x, then twice with respect to 

the 'default variable':: 

  

sage: derivative_parse([x, 2, 2]) 

[x, x, None, None] 

  

Special case with empty input list:: 

  

sage: derivative_parse([]) 

[None] 

  

sage: derivative_parse([-1]) 

Traceback (most recent call last): 

... 

ValueError: derivative counts must be non-negative 

  

Special case with single list argument provided:: 

  

sage: derivative_parse(([x, y], )) 

[x, y] 

  

If only the count is supplied:: 

  

sage: derivative_parse([0]) 

[] 

sage: derivative_parse([1]) 

[None] 

sage: derivative_parse([2]) 

[None, None] 

sage: derivative_parse([int(2)]) 

[None, None] 

  

Various other cases:: 

  

sage: derivative_parse([x]) 

[x] 

sage: derivative_parse([x, x]) 

[x, x] 

sage: derivative_parse([x, 2]) 

[x, x] 

sage: derivative_parse([x, 0]) 

[] 

sage: derivative_parse([x, y, x, 2, 2, y]) 

[x, y, x, x, None, None, y] 

  

""" 

if not args: 

return [None] 

if len(args) == 1 and isinstance(args[0], list): 

return args[0] 

  

output = [] 

cdef bint got_var = 0 # have a variable saved up from last loop? 

cdef int count, i 

  

for arg in args: 

if isinstance(arg, (int, Integer)): 

# process iteration count 

count = int(arg) 

if count < 0: 

raise ValueError("derivative counts must be non-negative") 

if not got_var: 

var = None 

for i from 0 <= i < count: 

output.append(var) 

got_var = 0 

else: 

# process variable 

if got_var: 

output.append(var) 

got_var = 1 

var = arg 

  

if got_var: 

output.append(var) 

  

return output 

  

  

def multi_derivative(F, args): 

r""" 

Calls F._derivative(var) for a sequence of variables specified by args. 

  

INPUT: 

  

F -- any object with a _derivative(var) method. 

args -- any tuple that can be processed by derivative_parse(). 

  

EXAMPLES:: 

  

sage: from sage.misc.derivative import multi_derivative 

sage: R.<x, y, z> = PolynomialRing(QQ) 

sage: f = x^3 * y^4 * z^5 

sage: multi_derivative(f, (x,)) # like f.derivative(x) 

3*x^2*y^4*z^5 

sage: multi_derivative(f, (x, y, x)) # like f.derivative(x, y, x) 

24*x*y^3*z^5 

sage: multi_derivative(f, ([x, y, x],)) # like f.derivative([x, y, x]) 

24*x*y^3*z^5 

sage: multi_derivative(f, (x, 2)) # like f.derivative(x, 2) 

6*x*y^4*z^5 

  

:: 

  

sage: R.<x> = PolynomialRing(QQ) 

sage: f = x^4 + x^2 + 1 

sage: multi_derivative(f, []) # like f.derivative() 

4*x^3 + 2*x 

sage: multi_derivative(f, [[]]) # like f.derivative([]) 

x^4 + x^2 + 1 

sage: multi_derivative(f, [x]) # like f.derivative(x) 

4*x^3 + 2*x 

""" 

if not args: 

# fast version where no arguments supplied 

return F._derivative() 

  

for arg in derivative_parse(args): 

F = F._derivative(arg) 

return F