ToC

Variational Mechanics

(def coordinate-tuple up)
#object[emmy.structure$up 0x11bf9653 "
emmy.structure$up@11bf9653"
]
(def velocity-tuple up)
#object[emmy.structure$up 0x11bf9653 "
emmy.structure$up@11bf9653"
]
(def acceleration-tuple up)
#object[emmy.structure$up 0x11bf9653 "
emmy.structure$up@11bf9653"
]
(def momentum-tuple down)
#object[emmy.structure$down 0x5ee76ea1 "
emmy.structure$down@5ee76ea1"
]

Lagrangian mechanics requires a configuration space Q, and a function L:RxQxQ' --> R

Mechanical systems have state at each instant. The state is the information required, along with the equations of motion, to determine the future of the system.

At every instant a system has a kinematic state, which has the time, the configuration, and the rate of change of the configuration. Lagrangian mechanics is formulated in terms of the kinematic state.

Kinematic states and their derivatives are represented as Scheme vectors, with components time, configuration, and derivatives.

(defn Lagrangian
"Returns a function signature for a Lagrangian with n degrees of freedom (or an
unrestricted number if n is not given).
Useful for constructing Lagrangian literal functions."
([] '(-> (UP Real (UP* Real) (UP* Real)) Real))
([n]
(r/template
(-> (UP Real (UP* Real ~n) (UP* Real ~n)) Real))))
#object[emmy.mechanics.lagrange$Lagrangian 0x38fc3733 "
emmy.mechanics.lagrange$Lagrangian@38fc3733"
]
(defn ->L-state
"Given a time `t`, coordinate tuple (or scalar) `q`, velocity tuple (or scalar)
`qdot` and any number of additional higher-order derivative tuples (or
scalars), returns a 'Local tuple', i.e., the state expected by a Lagrangian."
[t q qdot & derivs]
(apply up t q qdot derivs))
#object[emmy.mechanics.lagrange$__GT_L_state 0x3fc62f35 "
emmy.mechanics.lagrange$__GT_L_state@3fc62f35"
]
(def ->local
"Alias for [[->L-state]]."
->L-state)
#object[emmy.mechanics.lagrange$__GT_L_state 0x3fc62f35 "
emmy.mechanics.lagrange$__GT_L_state@3fc62f35"
]
(def ->state
"Alias for [[->L-state]]."
->L-state)
#object[emmy.mechanics.lagrange$__GT_L_state 0x3fc62f35 "
emmy.mechanics.lagrange$__GT_L_state@3fc62f35"
]

Local Tuple Selectors

(defn time
"Extract the time slot from a state tuple.
See [[coordinate]] for more detail."
[local]
{:pre [(up? local) (> (count local) 0)]}
(nth local 0))
#object[emmy.mechanics.lagrange$time 0x52263b90 "
emmy.mechanics.lagrange$time@52263b90"
]
(defn coordinate
"A convenience function on local tuples. A local tuple describes
the state of a system at a particular time:
```
[t, q, D q, D^2 q]
```
representing time, position, velocity (and optionally acceleration etc.)
[[coordinate]] returns the `q` element, which is expected to be a mapping from
time to a structure of coordinates."
[local]
{:pre [(up? local) (> (count local) 1)]}
(nth local 1))
#object[emmy.mechanics.lagrange$coordinate 0x37d1c513 "
emmy.mechanics.lagrange$coordinate@37d1c513"
]
(defn velocity
"Returns the velocity element of a local tuple (by convention, the third
element).
See [[coordinate]] for more detail."
[local]
{:pre [(up? local) (> (count local) 2)]}
(nth local 2))
#object[emmy.mechanics.lagrange$velocity 0x6ecd2975 "
emmy.mechanics.lagrange$velocity@6ecd2975"
]
(defn acceleration
"Returns the acceleration element of a local tuple (by convention, the fourth
element).
See [[coordinate]] for more detail."
[local]
{:pre [(up? local) (> (count local) 3)]}
(nth local 3))
#object[emmy.mechanics.lagrange$acceleration 0x60fc1c1e "
emmy.mechanics.lagrange$acceleration@60fc1c1e"
]
(defn state->n-dof [state]
{:pre [(s/structure? state)]}
(let [q (nth state 1)]
(if (up? q)
(count q)
1)))
#object[emmy.mechanics.lagrange$state__GT_n_dof 0x365412a "
emmy.mechanics.lagrange$state__GT_n_dof@365412a"
]

Aliases for the selectors above, included for parity with scmutils:

(def state->t
"Alias for [[time]]."
time)
#object[emmy.mechanics.lagrange$time 0x52263b90 "
emmy.mechanics.lagrange$time@52263b90"
]
(def state->q
"Alias for [[coordinate]]."
coordinate)
#object[emmy.mechanics.lagrange$coordinate 0x37d1c513 "
emmy.mechanics.lagrange$coordinate@37d1c513"
]
(def state->qdot
"Alias for [[velocity]]."
velocity)
#object[emmy.mechanics.lagrange$velocity 0x6ecd2975 "
emmy.mechanics.lagrange$velocity@6ecd2975"
]
(def state->qddot
"Alias for [[acceleration]]."
acceleration)
#object[emmy.mechanics.lagrange$acceleration 0x60fc1c1e "
emmy.mechanics.lagrange$acceleration@60fc1c1e"
]
(def coordinates
"Alias for [[coordinate]]."
coordinate)
#object[emmy.mechanics.lagrange$coordinate 0x37d1c513 "
emmy.mechanics.lagrange$coordinate@37d1c513"
]
(def velocities
"Alias for [[velocity]]."
velocity)
#object[emmy.mechanics.lagrange$velocity 0x6ecd2975 "
emmy.mechanics.lagrange$velocity@6ecd2975"
]
(def accelerations
"Alias for [[acceleration]]."
acceleration)
#object[emmy.mechanics.lagrange$acceleration 0x60fc1c1e "
emmy.mechanics.lagrange$acceleration@60fc1c1e"
]
(def Q
"Alias for [[coordinate]]."
coordinate)
#object[emmy.mechanics.lagrange$coordinate 0x37d1c513 "
emmy.mechanics.lagrange$coordinate@37d1c513"
]
(def Qdot
"Alias for [[velocity]]."
velocity)
#object[emmy.mechanics.lagrange$velocity 0x6ecd2975 "
emmy.mechanics.lagrange$velocity@6ecd2975"
]
(def Qdotdot
"Alias for [[acceleration]]."
acceleration)
#object[emmy.mechanics.lagrange$acceleration 0x60fc1c1e "
emmy.mechanics.lagrange$acceleration@60fc1c1e"
]
(defn literal-Lagrangian-state [n-dof]
(up (gensym 't)
(s/literal-up (gensym 'x) n-dof)
(s/literal-up (gensym 'v) n-dof)))
#object[emmy.mechanics.lagrange$literal_Lagrangian_state 0x3a25f508 "
emmy.mechanics.lagrange$literal_Lagrangian_state@3a25f508"
]

Chapter 1

Paths in the configuration manifold are functions that give a configuration for each time. From such a path we can construct a path in the kinematic state space. If such a path is described in terms of generalized coordinates, we have

(defn Gamma
"Gamma takes a path function (from time to coordinates) to a state
function (from time to local tuple)."
([q]
(let [Dq (D q)]
(-> (fn [t]
(up t (q t) (Dq t)))
(f/with-arity [:exactly 1]))))
([q n]
{:pre [(> n 1)]}
(let [Dqs (take (dec n) (iterate D q))
local (into (up identity) Dqs)]
(-> (fn [t] (local t))
(f/with-arity [:exactly 1])))))
#object[emmy.mechanics.lagrange$Gamma 0x3da4f5b8 "
emmy.mechanics.lagrange$Gamma@3da4f5b8"
]
(def path->state-path Gamma)
#object[emmy.mechanics.lagrange$Gamma 0x3da4f5b8 "
emmy.mechanics.lagrange$Gamma@3da4f5b8"
]

Lagrangians

A Lagrangian is an example of an L-function. An L-function takes a scalar argument and 2 vector arguments (t, q, q-dot). An L-function produces a scalar result.

(defn make-Lagrangian [kinetic-energy potential-energy]
(- kinetic-energy potential-energy))
#object[emmy.mechanics.lagrange$make_Lagrangian 0x3db802fe "
emmy.mechanics.lagrange$make_Lagrangian@3db802fe"
]

Library of Lagrangians

These should arguably live in their own place.

(defn L-free-particle
"The lagrangian of a free particle of mass m. The Lagrangian
returned is a function of the local tuple. Since the particle
is free, there is no potential energy, so the Lagrangian is
just the kinetic energy."
[mass]
(fn [[_ _ v]]
(* (/ 1 2) mass (g/square v))))
#object[emmy.mechanics.lagrange$L_free_particle 0x147d7872 "
emmy.mechanics.lagrange$L_free_particle@147d7872"
]
(defn L-rectangular
"Lagrangian for a point mass on with the potential energy V(x, y)"
[m V]
(fn [[_ [q0 q1] qdot]]
(- (* (/ 1 2) m (g/square qdot))
(V q0 q1))))
#object[emmy.mechanics.lagrange$L_rectangular 0x1e55240 "
emmy.mechanics.lagrange$L_rectangular@1e55240"
]
(defn L-harmonic
"The Lagrangian of a simple harmonic oscillator (mass-spring
system). m is the mass and k is the spring constant used in
Hooke's law. The resulting Lagrangian is a function of the
local tuple of the system."
[m k]
(fn [[_ q v]]
(- (* (/ 1 2) m (g/square v)) (* (/ 1 2) k (g/square q)))))
#object[emmy.mechanics.lagrange$L_harmonic 0x1bf67ef1 "
emmy.mechanics.lagrange$L_harmonic@1bf67ef1"
]
(defn L-uniform-acceleration
"The Lagrangian of an object experiencing uniform acceleration
in the negative y direction, i.e. the acceleration due to gravity"
[m g]
(fn [[_ [_ y] v]]
(- (* (/ 1 2) m (g/square v)) (* m g y))))
#object[emmy.mechanics.lagrange$L_uniform_acceleration 0x66a43083 "
emmy.mechanics.lagrange$L_uniform_acceleration@66a43083"
]
(defn L-central-rectangular [m U]
(fn [[_ q v]]
(- (* (/ 1 2) m (g/square v))
(U (g/abs q)))))
#object[emmy.mechanics.lagrange$L_central_rectangular 0x19656acd "
emmy.mechanics.lagrange$L_central_rectangular@19656acd"
]
(defn L-central-polar
"Consider planar motion in a central force field, with an arbitrary potential,
`U`, depending only on the radius. The generalized coordinates are polar."
[m U]
(fn [[_ [r] [rdot φdot]]]
(- (* (/ 1 2) m
(+ (g/square rdot)
(g/square (* r φdot))))
(U r))))
#object[emmy.mechanics.lagrange$L_central_polar 0x32b94cf3 "
emmy.mechanics.lagrange$L_central_polar@32b94cf3"
]
(defn L-Kepler-polar [GM m]
(fn [[_ [r] [rdot phidot]]]
(+ (* (/ 1 2) m
(+ (g/square rdot)
(g/square (* r phidot))))
(/ (* GM m) r))))
#object[emmy.mechanics.lagrange$L_Kepler_polar 0x1a90ada3 "
emmy.mechanics.lagrange$L_Kepler_polar@1a90ada3"
]
(defn L-axisymmetric-top [A C gMR]
(fn [[_ [theta] [thetadot phidot psidot]]]
(+ (* (/ 1 2) A
(+ (g/square thetadot)
(g/square (* phidot (sin theta)))))
(* (/ 1 2) C
(g/square (+ psidot (* phidot (cos theta)))))
(* -1 gMR (cos theta)))))
#object[emmy.mechanics.lagrange$L_axisymmetric_top 0x5df7b65a "
emmy.mechanics.lagrange$L_axisymmetric_top@5df7b65a"
]

Coupled harmonic oscillators.

(defn L-coupled-harmonic [m k]
(fn [[_ q qdot]]
(- (* (/ 1 2) qdot m qdot)
(* (/ 1 2) q k q))))
#object[emmy.mechanics.lagrange$L_coupled_harmonic 0x6ff69c2b "
emmy.mechanics.lagrange$L_coupled_harmonic@6ff69c2b"
]
(defn ^:no-doc F-sliding-pend [l]
(fn [[_ [x theta]]]
(up (up x 0)
(up (+ x (* l (sin theta)))
(* -1 l (cos theta))))))
#object[emmy.mechanics.lagrange$F_sliding_pend 0x17508bf2 "
emmy.mechanics.lagrange$F_sliding_pend@17508bf2"
]
(defn ^:no-doc two-free [m1 m2 g]
(fn [[_ [[_ h1] [_ h2]] [v1 v2]]]
(- (* (/ 1 2)
(+ (* m1 (g/square v1))
(* m2 (g/square v2))))
(* g (+ (* m1 h1)
(* m2 h2))))))
#object[emmy.mechanics.lagrange$two_free 0x8b2d10e "
emmy.mechanics.lagrange$two_free@8b2d10e"
]
(declare F->C)
#object[emmy.mechanics.lagrange$F__GT_C 0x6897e324 "
emmy.mechanics.lagrange$F__GT_C@6897e324"
]
(defn L-sliding-pend
"Pendulum of mass m2 and length b, hanging from a support of mass m1 that is
free to move horizontally (from Groesberg, Advanced Mechanics, p. 72)"
[m1 m2 l g]
(compose (two-free m1 m2 g)
(F->C (F-sliding-pend l))))
#object[emmy.mechanics.lagrange$L_sliding_pend 0x33db2dd9 "
emmy.mechanics.lagrange$L_sliding_pend@33db2dd9"
]

Consider a simple pendulum with Rayleigh dissipation:

(defn L-pendulum [g m l]
(fn [[_ theta thetadot]]
(+ (* (/ 1 2) m (g/square (* l thetadot)))
(* g m l (cos theta)))))
#object[emmy.mechanics.lagrange$L_pendulum 0x20c72f4b "
emmy.mechanics.lagrange$L_pendulum@20c72f4b"
]
(defn Rayleigh-dissipation [k]
(fn [[_ _ qdot]]
(* qdot k qdot)))
#object[emmy.mechanics.lagrange$Rayleigh_dissipation 0x3ee3a0fc "
emmy.mechanics.lagrange$Rayleigh_dissipation@3ee3a0fc"
]
(defn L-two-particle [m1 m2 V]
(fn [[_ [x1 x2] [v1 v2]]]
(- (+ (* (/ 1 2) m1 (g/square v1))
(* (/ 1 2) m2 (g/square v2)))
(V x1 x2))))
#object[emmy.mechanics.lagrange$L_two_particle 0x693afac7 "
emmy.mechanics.lagrange$L_two_particle@693afac7"
]

Given a Lagrangian, we can obtain Lagrange's equations of motion.

(defn Lagrange-equations
([L]
(Lagrange-equations L nil))
([L dissipation-fn]
(fn [q]
(let [state-path (Gamma q)]
(- (D (compose ((partial 2) L) state-path))
(compose ((partial 1) L) state-path)
(if dissipation-fn
(- (compose ((partial 2) dissipation-fn) state-path))
0))))))
#object[emmy.mechanics.lagrange$Lagrange_equations 0x3e5b7dc "
emmy.mechanics.lagrange$Lagrange_equations@3e5b7dc"
]
(defn Lagrangian->acceleration
([L]
(Lagrangian->acceleration L nil))
([L dissipation-fn]
(let [P ((partial 2) L)
F ((partial 1) L)]
(g/solve-linear-left
((partial 2) P)
(- F
(if dissipation-fn
((partial 2) dissipation-fn)
0)
(+ ((partial 0) P)
(* ((partial 1) P) velocity)))))))
#object[emmy.mechanics.lagrange$Lagrangian__GT_acceleration 0x1ac16d9c "
emmy.mechanics.lagrange$Lagrangian__GT_acceleration@1ac16d9c"
]

Lagrange equations in first-order form

(defn qv->local-path [q v]
(fn [t]
(->local t (q t) (v t))))
#object[emmy.mechanics.lagrange$qv__GT_local_path 0x3986ca78 "
emmy.mechanics.lagrange$qv__GT_local_path@3986ca78"
]
(defn Lagrangian->state-derivative
"Optionally takes a dissipation function."
([L]
(Lagrangian->state-derivative L nil))
([L dissipation-fn]
(let [acceleration (Lagrangian->acceleration L dissipation-fn)]
(fn [state]
(up 1
(velocity state)
(acceleration state))))))
#object[emmy.mechanics.lagrange$Lagrangian__GT_state_derivative 0x754f34d "
emmy.mechanics.lagrange$Lagrangian__GT_state_derivative@754f34d"
]
(defn local-state-derivative
"The state derivative of a Lagrangian is a function carrying a state tuple to
its time derivative.
Alias for the non-dissipative, single-arity version
of [[Lagrangian->state-derivative]]."
[L]
(Lagrangian->state-derivative L nil))
#object[emmy.mechanics.lagrange$local_state_derivative 0x29a1ef2c "
emmy.mechanics.lagrange$local_state_derivative@29a1ef2c"
]
(defn Lagrange-equations-first-order [L]
(fn [q v]
(let [state-path (qv->local-path q v)]
(- (D state-path)
(compose (Lagrangian->state-derivative L)
state-path)))))
#object[emmy.mechanics.lagrange$Lagrange_equations_first_order 0x381dca09 "
emmy.mechanics.lagrange$Lagrange_equations_first_order@381dca09"
]
(def Lagrange-equations-1
"Alias for [[Lagrange-equations-first-order]]."
Lagrange-equations-first-order)
#object[emmy.mechanics.lagrange$Lagrange_equations_first_order 0x381dca09 "
emmy.mechanics.lagrange$Lagrange_equations_first_order@381dca09"
]

Given a Lagrangian, we can make an energy function on (t, Q, Qdot).

(defn Lagrangian->energy [L]
(let [P ((partial 2) L)]
(- (* P velocity) L)))
#object[emmy.mechanics.lagrange$Lagrangian__GT_energy 0x37471278 "
emmy.mechanics.lagrange$Lagrangian__GT_energy@37471278"
]

On a trajectory there may be power lost (if dissipation) The following produces the power lost.

(defn Lagrangian->power-loss [L]
(fn [q]
(D (compose
(Lagrangian->energy L)
(Gamma q)))))
#object[emmy.mechanics.lagrange$Lagrangian__GT_power_loss 0x17a95146 "
emmy.mechanics.lagrange$Lagrangian__GT_power_loss@17a95146"
]
(defn T3-spherical [m]
(fn [[_ [r theta] [rdot thetadot phidot]]]
(* (/ 1 2) m
(+ (g/square rdot)
(g/square (* r thetadot))
(g/square (* r (sin theta) phidot))))))
#object[emmy.mechanics.lagrange$T3_spherical 0x31571410 "
emmy.mechanics.lagrange$T3_spherical@31571410"
]
(defn L3-central [m Vr]
(letfn [(Vs [[_ [r]]]
(Vr r))]
(- (T3-spherical m) Vs)))
#object[emmy.mechanics.lagrange$L3_central 0x67cccdb1 "
emmy.mechanics.lagrange$L3_central@67cccdb1"
]
(defn Lagrangian-action
([L q t1 t2]
(Lagrangian-action L q t1 t2 {}))
([L q t1 t2 integration-opts]
(q/definite-integral
(compose L (Gamma q)) t1 t2 integration-opts)))
#object[emmy.mechanics.lagrange$Lagrangian_action 0x6897c7e2 "
emmy.mechanics.lagrange$Lagrangian_action@6897c7e2"
]
(defn linear-interpolants [x0 x1 n]
(let [n+1 (inc n)
dx (/ (- x1 x0) n+1)]
(for [i (range 1 n+1)]
(+ x0 (* i dx)))))
#object[emmy.mechanics.lagrange$linear_interpolants 0x356998d7 "
emmy.mechanics.lagrange$linear_interpolants@356998d7"
]
(defn Lagrange-interpolation-function
"Given `ys` (a sequence of function values) and `xs` (an equal-length sequence
of function inputs), returns a [[emmy.polynomial/Polynomial]] instance
guaranteed to pass through all supplied `xs` and `ys`.
The contract for inputs is that `(map vector xs ys)` should return a sequence
of pairs of points."
[ys xs]
(p/from-points
(map vector xs ys)))
#object[emmy.mechanics.lagrange$Lagrange_interpolation_function 0x3c97fdfe "
emmy.mechanics.lagrange$Lagrange_interpolation_function@3c97fdfe"
]
(defn make-path
"SICM p. 23n"
[t0 q0 t1 q1 qs]
(let [n (count qs)
ts (linear-interpolants t0 t1 n)]
(Lagrange-interpolation-function
`[~q0 ~@qs ~q1]
`[~t0 ~@ts ~t1])))
#object[emmy.mechanics.lagrange$make_path 0x3d371e98 "
emmy.mechanics.lagrange$make_path@3d371e98"
]
(defn parametric-path-action
"SICM p. 23"
[Lagrangian t0 q0 t1 q1]
(fn [qs]
(let [path (make-path t0 q0 t1 q1 qs)]
(Lagrangian-action
Lagrangian path t0 t1
{:compile? false}))))
#object[emmy.mechanics.lagrange$parametric_path_action 0x6bc9660b "
emmy.mechanics.lagrange$parametric_path_action@6bc9660b"
]
(defn find-path
"SICM p. 23. The optional parameter values is a callback which will report
intermediate points of the minimization."
[Lagrangian t0 q0 t1 q1 n & {:keys [observe]}]
(let [initial-qs (linear-interpolants q0 q1 n)
minimizing-qs (m/multidimensional-minimize
(parametric-path-action Lagrangian t0 q0 t1 q1)
initial-qs
:callback observe)]
(make-path t0 q0 t1 q1 minimizing-qs)))
#object[emmy.mechanics.lagrange$find_path 0x121fe485 "
emmy.mechanics.lagrange$find_path@121fe485"
]

An alternative method allows taking derivatives in the construction of the Lagrangian.

(defn osculating-path
"Given a state tuple (of finite length), reconstitutes the initial segment of
the Taylor series corresponding to the state tuple data as a function of t.
Time is measured beginning at the point of time specified in the input state
tuple."
[state0]
(let [[t0 q0] state0
k (count state0)]
(fn [t]
(let [dt (- t t0)]
(loop [n 2 sum q0 dt**n:n! dt]
(if (= n k)
sum
(recur (inc n)
(+ sum (* (nth state0 n) dt**n:n!))
(/ (* dt**n:n! dt) n))))))))
#object[emmy.mechanics.lagrange$osculating_path 0x11e49335 "
emmy.mechanics.lagrange$osculating_path@11e49335"
]
(defn Gamma-bar [f]
(fn [local]
((f (osculating-path local)) (first local))))
#object[emmy.mechanics.lagrange$Gamma_bar 0x14a29c4f "
emmy.mechanics.lagrange$Gamma_bar@14a29c4f"
]

"Total Time Derivative"

(defn Dt-procedure [F]
(fn DtF [state]
(let [n (count state)]
(letfn [(DF-on-path [q]
(D (f/compose F (Gamma q (dec n)))))]
((Gamma-bar DF-on-path) state)))))
#object[emmy.mechanics.lagrange$Dt_procedure 0x4aa70c2a "
emmy.mechanics.lagrange$Dt_procedure@4aa70c2a"
]
(def Dt (o/make-operator Dt-procedure 'Dt))
Dt
(defn- trim-last-argument [local]
(s/up* (pop (s/structure->vector local))))
#object[emmy.mechanics.lagrange$trim_last_argument 0x347b59ee "
emmy.mechanics.lagrange$trim_last_argument@347b59ee"
]
(defn Euler-Lagrange-operator [L]
(- (Dt ((partial 2) L))
(compose ((partial 1) L) trim-last-argument)))
#object[emmy.mechanics.lagrange$Euler_Lagrange_operator 0x59ada828 "
emmy.mechanics.lagrange$Euler_Lagrange_operator@59ada828"
]
(def LE
"Alias for [[Euler-lagrange-operator]]."
Euler-Lagrange-operator)
#object[emmy.mechanics.lagrange$Euler_Lagrange_operator 0x59ada828 "
emmy.mechanics.lagrange$Euler_Lagrange_operator@59ada828"
]
(def Lagrange-equations-operator
"Alias for [[Euler-lagrange-operator]]."
Euler-Lagrange-operator)
#object[emmy.mechanics.lagrange$Euler_Lagrange_operator 0x59ada828 "
emmy.mechanics.lagrange$Euler_Lagrange_operator@59ada828"
]
(defn generalized-LE [Lagrangian]
(fn [state]
(let [m (count state)]
(assert (and (> m 3) (even? m))
"Incorrect state size for Lagrange Equations")
(letfn [(lp [i state]
(if (zero? i)
0
(- (((g/expt Dt (dec i))
((partial i) Lagrangian))
state)
(lp (dec i) (trim-last-argument state)))))]
(lp (quot m 2) state)))))
#object[emmy.mechanics.lagrange$generalized_LE 0x6c65f513 "
emmy.mechanics.lagrange$generalized_LE@6c65f513"
]

Coordinate Transformation to State Transformation

(defn F->C
"Accepts a coordinate transformation `F` from a local tuple to a new coordinate
structure, and returns a function from `local -> local` that applies the
transformation directly.
[[F->C]] handles local tuples of arbitrary length."
[F]
(fn C [local]
(let [n (count local)
f-bar (fn [q-prime]
(let [q (compose F (Gamma q-prime))]
(Gamma q n)))]
((Gamma-bar f-bar) local))))
#object[emmy.mechanics.lagrange$F__GT_C 0x6897e324 "
emmy.mechanics.lagrange$F__GT_C@6897e324"
]

The following transformations are applicable to configuration coordinates.

(defn rectangular->polar [[x y]]
(let [r (g/sqrt
(+ (g/square x)
(g/square y)))
phi (g/atan y x)]
(up r phi)))
#object[emmy.mechanics.lagrange$rectangular__GT_polar 0x6c255c34 "
emmy.mechanics.lagrange$rectangular__GT_polar@6c255c34"
]
(defn r->p [tqv]
(rectangular->polar
(coordinate tqv)))
#object[emmy.mechanics.lagrange$r__GT_p 0x27fcc77 "
emmy.mechanics.lagrange$r__GT_p@27fcc77"
]
(defn polar->rectangular [[r phi]]
(let [x (* r (cos phi))
y (* r (sin phi))]
(up x y)))
#object[emmy.mechanics.lagrange$polar__GT_rectangular 0x3627d8f8 "
emmy.mechanics.lagrange$polar__GT_rectangular@3627d8f8"
]
(defn p->r
"SICM p. 47. Polar to rectangular coordinates of state."
[tqv]
(polar->rectangular
(coordinate tqv)))
#object[emmy.mechanics.lagrange$p__GT_r 0x75a97e42 "
emmy.mechanics.lagrange$p__GT_r@75a97e42"
]

Spherical Coordinates (radius, colatitude, longitude)

(defn spherical->rectangular [[r theta phi]]
(let [x (* r (sin theta) (cos phi))
y (* r (sin theta) (sin phi))
z (* r (cos theta))]
(coordinate-tuple x y z)))
#object[emmy.mechanics.lagrange$spherical__GT_rectangular 0x332b483f "
emmy.mechanics.lagrange$spherical__GT_rectangular@332b483f"
]
(defn s->r
"SICM p. 83"
[local]
(spherical->rectangular
(coordinate local)))
#object[emmy.mechanics.lagrange$s__GT_r 0x4f4b2659 "
emmy.mechanics.lagrange$s__GT_r@4f4b2659"
]
(defn rectangular->spherical [[x y z]]
(let [r (g/sqrt (+ (g/square x)
(g/square y)
(g/square z)))
theta (g/acos (/ z r))
phi (g/atan y x)]
(coordinate-tuple r theta phi)))
#object[emmy.mechanics.lagrange$rectangular__GT_spherical 0x47a3d750 "
emmy.mechanics.lagrange$rectangular__GT_spherical@47a3d750"
]
(defn r->s [local]
(rectangular->spherical
(coordinate local)))
#object[emmy.mechanics.lagrange$r__GT_s 0x79c6ea88 "
emmy.mechanics.lagrange$r__GT_s@79c6ea88"
]