/
functions.py
149 lines (113 loc) · 4.49 KB
/
functions.py
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
r"""
Calculus functions
"""
from __future__ import absolute_import
from sage.matrix.all import matrix
from sage.structure.element import is_Matrix
from sage.structure.element import is_Vector
from sage.symbolic.ring import is_SymbolicVariable
from .functional import diff
def wronskian(*args):
"""
Return the Wronskian of the provided functions, differentiating with
respect to the given variable.
If no variable is provided, diff(f) is called for each function f.
wronskian(f1,...,fn, x) returns the Wronskian of f1,...,fn, with
derivatives taken with respect to x.
wronskian(f1,...,fn) returns the Wronskian of f1,...,fn where
k'th derivatives are computed by doing ``.derivative(k)`` on each
function.
The Wronskian of a list of functions is a determinant of derivatives.
The nth row (starting from 0) is a list of the nth derivatives of the
given functions.
For two functions::
| f g |
W(f, g) = det| | = f*g' - g*f'.
| f' g' |
EXAMPLES::
sage: wronskian(e^x, x^2)
-x^2*e^x + 2*x*e^x
sage: x,y = var('x, y')
sage: wronskian(x*y, log(x), x)
-y*log(x) + y
If your functions are in a list, you can use `*' to turn them into
arguments to :func:`wronskian`::
sage: wronskian(*[x^k for k in range(1, 5)])
12*x^4
If you want to use 'x' as one of the functions in the Wronskian,
you can't put it last or it will be interpreted as the variable
with respect to which we differentiate. There are several ways to
get around this.
Two-by-two Wronskian of sin(x) and e^x::
sage: wronskian(sin(x), e^x, x)
-cos(x)*e^x + e^x*sin(x)
Or don't put x last::
sage: wronskian(x, sin(x), e^x)
(cos(x)*e^x + e^x*sin(x))*x - 2*e^x*sin(x)
Example where one of the functions is constant::
sage: wronskian(1, e^(-x), e^(2*x))
-6*e^x
REFERENCES:
- :wikipedia:`Wronskian`
- http://planetmath.org/encyclopedia/WronskianDeterminant.html
AUTHORS:
- Dan Drake (2008-03-12)
"""
if not args:
raise TypeError('wronskian() takes at least one argument (0 given)')
elif len(args) == 1:
# a 1x1 Wronskian is just its argument
return args[0]
else:
if is_SymbolicVariable(args[-1]):
# if last argument is a variable, peel it off and
# differentiate the other args
v = args[-1]
fs = args[0:-1]
def row(n):
return [diff(f, v, n) for f in fs]
else:
# if the last argument is not a variable, just run
# .derivative on everything
fs = args
def row(n):
return [diff(f, n) for f in fs]
# NOTE: I rewrote the below as two lines to avoid a possible subtle
# memory management problem on some platforms (only VMware as far
# as we know?). See trac #2990.
# There may still be a real problem that this is just hiding for now.
return matrix([row(r) for r in range(len(fs))]).determinant()
def jacobian(functions, variables):
"""
Return the Jacobian matrix, which is the matrix of partial
derivatives in which the i,j entry of the Jacobian matrix is the
partial derivative diff(functions[i], variables[j]).
EXAMPLES::
sage: x,y = var('x,y')
sage: g=x^2-2*x*y
sage: jacobian(g, (x,y))
[2*x - 2*y -2*x]
The Jacobian of the Jacobian should give us the "second derivative", which is the Hessian matrix::
sage: jacobian(jacobian(g, (x,y)), (x,y))
[ 2 -2]
[-2 0]
sage: g.hessian()
[ 2 -2]
[-2 0]
sage: f=(x^3*sin(y), cos(x)*sin(y), exp(x))
sage: jacobian(f, (x,y))
[ 3*x^2*sin(y) x^3*cos(y)]
[-sin(x)*sin(y) cos(x)*cos(y)]
[ e^x 0]
sage: jacobian(f, (y,x))
[ x^3*cos(y) 3*x^2*sin(y)]
[ cos(x)*cos(y) -sin(x)*sin(y)]
[ 0 e^x]
"""
if is_Matrix(functions) and (functions.nrows()==1 or functions.ncols()==1):
functions = functions.list()
elif not (isinstance(functions, (tuple, list)) or is_Vector(functions)):
functions = [functions]
if not isinstance(variables, (tuple, list)) and not is_Vector(variables):
variables = [variables]
return matrix([[diff(f, v) for v in variables] for f in functions])