|
""" |
|
This module implements a method to find |
|
Euler-Lagrange Equations for given Lagrangian. |
|
""" |
|
from itertools import combinations_with_replacement |
|
from sympy.core.function import (Derivative, Function, diff) |
|
from sympy.core.relational import Eq |
|
from sympy.core.singleton import S |
|
from sympy.core.symbol import Symbol |
|
from sympy.core.sympify import sympify |
|
from sympy.utilities.iterables import iterable |
|
|
|
|
|
def euler_equations(L, funcs=(), vars=()): |
|
r""" |
|
Find the Euler-Lagrange equations [1]_ for a given Lagrangian. |
|
|
|
Parameters |
|
========== |
|
|
|
L : Expr |
|
The Lagrangian that should be a function of the functions listed |
|
in the second argument and their derivatives. |
|
|
|
For example, in the case of two functions $f(x,y)$, $g(x,y)$ and |
|
two independent variables $x$, $y$ the Lagrangian has the form: |
|
|
|
.. math:: L\left(f(x,y),g(x,y),\frac{\partial f(x,y)}{\partial x}, |
|
\frac{\partial f(x,y)}{\partial y}, |
|
\frac{\partial g(x,y)}{\partial x}, |
|
\frac{\partial g(x,y)}{\partial y},x,y\right) |
|
|
|
In many cases it is not necessary to provide anything, except the |
|
Lagrangian, it will be auto-detected (and an error raised if this |
|
cannot be done). |
|
|
|
funcs : Function or an iterable of Functions |
|
The functions that the Lagrangian depends on. The Euler equations |
|
are differential equations for each of these functions. |
|
|
|
vars : Symbol or an iterable of Symbols |
|
The Symbols that are the independent variables of the functions. |
|
|
|
Returns |
|
======= |
|
|
|
eqns : list of Eq |
|
The list of differential equations, one for each function. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import euler_equations, Symbol, Function |
|
>>> x = Function('x') |
|
>>> t = Symbol('t') |
|
>>> L = (x(t).diff(t))**2/2 - x(t)**2/2 |
|
>>> euler_equations(L, x(t), t) |
|
[Eq(-x(t) - Derivative(x(t), (t, 2)), 0)] |
|
>>> u = Function('u') |
|
>>> x = Symbol('x') |
|
>>> L = (u(t, x).diff(t))**2/2 - (u(t, x).diff(x))**2/2 |
|
>>> euler_equations(L, u(t, x), [t, x]) |
|
[Eq(-Derivative(u(t, x), (t, 2)) + Derivative(u(t, x), (x, 2)), 0)] |
|
|
|
References |
|
========== |
|
|
|
.. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation |
|
|
|
""" |
|
|
|
funcs = tuple(funcs) if iterable(funcs) else (funcs,) |
|
|
|
if not funcs: |
|
funcs = tuple(L.atoms(Function)) |
|
else: |
|
for f in funcs: |
|
if not isinstance(f, Function): |
|
raise TypeError('Function expected, got: %s' % f) |
|
|
|
vars = tuple(vars) if iterable(vars) else (vars,) |
|
|
|
if not vars: |
|
vars = funcs[0].args |
|
else: |
|
vars = tuple(sympify(var) for var in vars) |
|
|
|
if not all(isinstance(v, Symbol) for v in vars): |
|
raise TypeError('Variables are not symbols, got %s' % vars) |
|
|
|
for f in funcs: |
|
if not vars == f.args: |
|
raise ValueError("Variables %s do not match args: %s" % (vars, f)) |
|
|
|
order = max([len(d.variables) for d in L.atoms(Derivative) |
|
if d.expr in funcs] + [0]) |
|
|
|
eqns = [] |
|
for f in funcs: |
|
eq = diff(L, f) |
|
for i in range(1, order + 1): |
|
for p in combinations_with_replacement(vars, i): |
|
eq = eq + S.NegativeOne**i*diff(L, diff(f, *p), *p) |
|
new_eq = Eq(eq, 0) |
|
if isinstance(new_eq, Eq): |
|
eqns.append(new_eq) |
|
|
|
return eqns |
|
|