In [46]:
from operator import attrgetter
from sympy import *
init_printing()
In [2]:
f, L, w = Function('f'), Function('L'), Function('w') # abstract, Lagrangian and path functions, respectively
t, q, q_point = symbols(r't q \dot{q}') # symbols for the Leibniz notation
In [3]:
Lagrangian_eq = Eq(Derivative(Derivative(L(t, q, q_point),q_point,evaluate=False),
t, evaluate=False) - L(t,q,q_point).diff(q),0)
Lagrangian_eq # compact Lagrangian equation, implicit indeed
Out[3]:
In [4]:
Lagrangian_eq = Eq(Derivative(Subs(L(t, q, q_point).diff(q_point), [q,q_point], [w(t),w(t).diff(t)]),t) -
Subs(L(t,q,q_point).diff(q), [q,q_point], [w(t),w(t).diff(t)]),0)
Lagrangian_eq
Out[4]:
In [5]:
Lagrangian_eq.doit() # a complex explosion by automatic computation
Out[5]:
In [6]:
def diff_positional(f, i):
a = IndexedBase('a')
der = f.diff(f.args[i])
def D(*args):
#return Lambda([a[i] for i in range(len(f.args))],
return der.subs({f.args[i]:args[i] for i in range(len(f.args))}, simultaneous=True)
return D # function D is a function of the meta-language, not in the object language
In [7]:
diff_positional(L(t, q, q_point), 2)(t,w(t),w(t).diff(t)) # :/
Out[7]:
In [8]:
def diff_positional(f, i):
return Function(r'\partial_{{{}}}{}'.format(i, str(f))) # the \partial is just a symbol, it hasn't meaning
In [9]:
(Derivative(diff_positional(L, 2)(t,w(t), w(t).diff(t)), t) -
diff_positional(L, 1)(t,w(t), w(t).diff(t))) # :(
Out[9]:
In [10]:
Lagrangian_eq = Eq(Derivative(L(t,w(t), w(t).diff(t)).fdiff(argindex=3),t, evaluate=False) -
L(t,w(t), w(t).diff(t)).fdiff(argindex=2),
0, evaluate=False)
Lagrangian_eq # :) , although it doesn't use "positional derivative" operator explicitly
Out[10]:
In [11]:
def Derivative_eq(f, argindex=1):
d = Dummy()
args = [d if i+1 == argindex else a for i,a in enumerate(f.args)]
lhs = f.fdiff(argindex)
rhs = Subs(f.func(*args).diff(d), d, f.args[argindex-1])
return Eq(lhs, rhs, evaluate=False)
Derivative_eq(f(t,q,q_point),2) # applicative Derivative operator
Out[11]:
In [12]:
def Gamma(w):
return Lambda([t], (t, w(t), w(t).diff(t))) # state-space function
In [13]:
Gamma(w), Gamma(w)(t)
Out[13]:
In [14]:
Lagrangian_eq = Eq(Derivative(L(*Gamma(w)(t)).fdiff(argindex=3),t, evaluate=False) -
L(t,w(t), w(t).diff(t)).fdiff(argindex=2),
0, evaluate=False)
Lagrangian_eq
Out[14]:
In [15]:
class FunctionsComposition(Function):
nargs = 2
def _latex(self, sexp):
return r' \circ '.join(map(latex,
map(lambda a: a.func if isinstance(a, Function) else a,
self.args)))
def _eval_subs(self, old, new):
f, g = self.args
if old == f:
return new.subs({f.args[0]:g}, simultaneous=True)
In [22]:
F_o_w = FunctionsComposition(Function(r'\mathcal{F}')(t), w(t))
F_o_w
Out[22]:
In [23]:
F_o_w.subs({Function(r'\mathcal{F}')(t):1/(1-t)})
Out[23]:
In [24]:
F_o_w.subs({w(t):2*t})
Out[24]:
In [25]:
_.subs({Function(r'\mathcal{F}')(t):2*t+1})
Out[25]:
In [26]:
FunctionsComposition(L(t, w(t), w(t).diff(t)).fdiff(argindex=3),Gamma(w))
Out[26]:
In [40]:
m,v,k,q = symbols('m v k q')
Lagrangian_eq.subs({L:Lambda([t,q,v], (m*v**2)/2-(k*q**2)/2)}) # plug in the Lagrangian function
Out[40]:
In [41]:
eq = _.doit() # do derivatives
eq
Out[41]:
In [42]:
a, omega, phi = symbols(r'a \omega \phi')
_.subs({w(t):a*cos(omega*t+phi)})
Out[42]:
In [43]:
_.doit().factor()
Out[43]:
In [44]:
solve(_, omega)
Out[44]:
In [45]:
dsolve(eq, w(t)) # solve with respect to path function w(t)
Out[45]:
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.