Degenerate Lagrangian Systems

A Lagrangian $L(x,v)$ is said to be degenerate if the determinant of the Hessian with respect to the velocities vanishes, i.e.,

\[\left\vert \frac{\partial^2 L}{\partial v^i \, \partial v^j} \right\vert = 0 .\]

The Euler-Lagrange equations,

\[\frac{d}{dt} \frac{\partial L}{\partial v} - \frac{\partial L}{\partial x} = 0 ,\]

of such Lagrangians are a set of first-order ordinary differential equations and not second-order differential equations as for non-degenerate Lagrangians.

Of particular interest in various applications are degenerate Lagrangians of the form

\[L(x,v) = \vartheta(x) \cdot v - H (x) .\]

Their Euler-Lagrange equations take the form

\[\frac{d \vartheta}{dt} (x) = \nabla \vartheta(x) \cdot v - \nabla H (x) .\]

We exemplify this with the Lotka-Volterra problem in 2d.

Lotka-Volterra

Before any use, we need to load EulerLagrange:

using EulerLagrange
using LinearAlgebra

Next, we generate symbolic variables for a two-dimensional Lagrangian system:

t, x, v = lagrangian_variables(2)
(t, (x(t))[1:2], (v(t))[1:2])

We define a named tuple with typical values for the parameters, e.g.,

params = (
    a₁ = -1.0,
    a₂ = -1.0,
    b₁ = 1.0,
    b₂ = 2.0,
)
(a₁ = -1.0, a₂ = -1.0, b₁ = 1.0, b₂ = 2.0)

We use the function symbolize to generate a symbolic version of the parameters:

sparams = symbolize(params)
(a₁ = a₁ₚ, a₂ = a₂ₚ, b₁ = b₁ₚ, b₂ = b₂ₚ)

Define the Hamiltonian function and the symplectic potential:

ϑ(x, params) = [log(x[2]) / x[1] / 2, - log(x[1]) / x[2] / 2]
H(x, params) = params.a₁ * x[1] + params.a₂ * x[2] + params.b₁ * log(x[1]) + params.b₂ * log(x[2])
H (generic function with 1 method)

The Hamiltonian and the symplectic potential, evaluated on and together with the symbolic variables and parameters are used to construct a DegenerateLagrangianSystem:

lag_sys = DegenerateLagrangianSystem(ϑ(x,sparams) ⋅ v, H(x,sparams), t, x, v, sparams)

Degenerate Lagrangian system with

L = ((v(t))[1]*(x(t))[2]*log((x(t))[2]) - (v(t))[2]*(x(t))[1]*log((x(t))[1])) / (2(x(t))[1]*(x(t))[2]) - a₁ₚ*(x(t))[1] - a₂ₚ*(x(t))[2] - b₁ₚ*log((x(t))[1]) - b₂ₚ*log((x(t))[2])

The constructor computes the Euler-Lagrange equations and generates the corresponding Julia code.

In the last step, we can now construct a LODEProblem from the LagrangianSystem and some appropriate initial conditions, a time span to integrate over and a time step:

tspan = (0.0, 10.0)
tstep = 0.01

q₀ = [2.0, 1.0]
p₀ = ϑ(q₀, params)

lprob = LODEProblem(lag_sys, tspan, tstep, q₀, p₀; parameters = params)
Geometric Equation Problem for Lagrangian Ordinary Differential Equation (LODE)

 with vector fields
   ϑ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xf311f19d, 0xc8b557ea, 0xc98bcd8a, 0xe5ab0856, 0x025e67e8), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = log(getindex(X, 2)) / (2 * getindex(X, 1))
                        #= none:11 =#
                        ˍ₋out[2] = (-1 * log(getindex(X, 1))) / (2 * getindex(X, 2))
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end)
   f = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd2048f60, 0xa54fe3ba, 0x30cda328, 0xb7cf5a3d, 0x12d102a3), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = ((-1 * params.a₁ + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1) ^ 2) * getindex(X, 2))) + (-1 * params.b₁) / getindex(X, 1)) + (-1 * getindex(V, 2) + (-1 * getindex(V, 2)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2))
                        #= none:11 =#
                        ˍ₋out[2] = ((-1 * params.a₂ + (getindex(V, 1) + getindex(V, 1) * log(getindex(X, 2))) / ((2 * getindex(X, 1)) * getindex(X, 2))) + (-1 * params.b₂) / getindex(X, 2)) + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2) ^ 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end)
   g = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x20813b47, 0x473ac96b, 0x125c3108, 0x71639974, 0x81831468), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1) ^ 2) * getindex(X, 2)) + (-1 * getindex(V, 2) + (-1 * getindex(V, 2)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2))
                        #= none:11 =#
                        ˍ₋out[2] = (getindex(V, 1) + getindex(V, 1) * log(getindex(X, 2))) / ((2 * getindex(X, 1)) * getindex(X, 2)) + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2) ^ 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end)

 Lagrangian: L = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfa7d8373, 0x88a78a96, 0x63af3756, 0x9028d5fb, 0xed7d87f2), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                (((((getindex(V, 1) * getindex(X, 2)) * log(getindex(X, 2)) + ((-1 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2)) + (-1 * getindex(X, 1)) * params.a₁) + (-1 * getindex(X, 2)) * params.a₂) + (-1 * params.b₁) * log(getindex(X, 1))) + (-1 * params.b₂) * log(getindex(X, 2))
            end
        end
end)

 Invariants: 
   (h = EulerLagrange.var"#102#103"{@NamedTuple{L::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfa7d8373, 0x88a78a96, 0x63af3756, 0x9028d5fb, 0xed7d87f2), Expr}, H::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xac5bfab4, 0xa9024449, 0x9c498a28, 0x059148de, 0xa4bbd30d), Expr}, EL::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd973ae68, 0xc3ced41a, 0xdefe1f56, 0x2eb4eba4, 0xa31fc8f3), Expr}, ∇H::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9bea2bf4, 0xefb3213d, 0x0dd89dc5, 0x2cc8b930, 0x75d17729), Expr}, ẋ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcc398c5d, 0x520167e0, 0x43877207, 0xb23eb456, 0xd7a36a2c), Expr}, v::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcc398c5d, 0x520167e0, 0x43877207, 0xb23eb456, 0xd7a36a2c), Expr}, f::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd2048f60, 0xa54fe3ba, 0x30cda328, 0xb7cf5a3d, 0x12d102a3), Expr}, u::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd20c7564, 0xd9f14488, 0x7c9632d0, 0x567848cf, 0x0ce88cdb), Expr}, g::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x20813b47, 0x473ac96b, 0x125c3108, 0x71639974, 0x81831468), Expr}, ū::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd20c7564, 0xd9f14488, 0x7c9632d0, 0x567848cf, 0x0ce88cdb), Expr}, ḡ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe5f4d276, 0x24c3195f, 0x52977c34, 0xb7208624, 0xe37a73af), Expr}, p::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe9912e1f, 0xebb1dd3e, 0x53c1640c, 0x7293ae55, 0x7aada184), Expr}, ϑ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xf311f19d, 0xc8b557ea, 0xc98bcd8a, 0xe5ab0856, 0x025e67e8), Expr}, ω::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x6e2eecfa, 0x18781c0d, 0xabb45a2a, 0xeb27d0b1, 0x1a280cff), Expr}, ϕ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfefbd262, 0xde882f29, 0x3ed25564, 0x5fcbc742, 0x4908734c), Expr}, ψ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :F, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x83e5ca8d, 0xbf3d8275, 0xe53986f9, 0xfc32d56b, 0x0d923dba), Expr}, P::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe4448603, 0x32b58c2a, 0xd43f4eae, 0xcefa934f, 0xef815687), Expr}}}((L = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfa7d8373, 0x88a78a96, 0x63af3756, 0x9028d5fb, 0xed7d87f2), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                (((((getindex(V, 1) * getindex(X, 2)) * log(getindex(X, 2)) + ((-1 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2)) + (-1 * getindex(X, 1)) * params.a₁) + (-1 * getindex(X, 2)) * params.a₂) + (-1 * params.b₁) * log(getindex(X, 1))) + (-1 * params.b₂) * log(getindex(X, 2))
            end
        end
end), H = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xac5bfab4, 0xa9024449, 0x9c498a28, 0x059148de, 0xa4bbd30d), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                ((getindex(X, 1) * params.a₁ + getindex(X, 2) * params.a₂) + params.b₁ * log(getindex(X, 1))) + params.b₂ * log(getindex(X, 2))
            end
        end
end), EL = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd973ae68, 0xc3ced41a, 0xdefe1f56, 0x2eb4eba4, 0xa31fc8f3), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = -1 * params.a₁ + (-1 * params.b₁) / getindex(X, 1)
                        #= none:11 =#
                        ˍ₋out[2] = -1 * params.a₂ + (-1 * params.b₂) / getindex(X, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ∇H = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9bea2bf4, 0xefb3213d, 0x0dd89dc5, 0x2cc8b930, 0x75d17729), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = params.a₁ + params.b₁ / getindex(X, 1)
                        #= none:11 =#
                        ˍ₋out[2] = params.a₂ + params.b₂ / getindex(X, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ẋ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcc398c5d, 0x520167e0, 0x43877207, 0xb23eb456, 0xd7a36a2c), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(X, 1) * (params.b₂ + getindex(X, 2) * params.a₂)
                        #= none:11 =#
                        ˍ₋out[2] = (-1 * (params.b₁ + getindex(X, 1) * params.a₁)) * getindex(X, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), v = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcc398c5d, 0x520167e0, 0x43877207, 0xb23eb456, 0xd7a36a2c), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(X, 1) * (params.b₂ + getindex(X, 2) * params.a₂)
                        #= none:11 =#
                        ˍ₋out[2] = (-1 * (params.b₁ + getindex(X, 1) * params.a₁)) * getindex(X, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), f = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd2048f60, 0xa54fe3ba, 0x30cda328, 0xb7cf5a3d, 0x12d102a3), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = ((-1 * params.a₁ + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1) ^ 2) * getindex(X, 2))) + (-1 * params.b₁) / getindex(X, 1)) + (-1 * getindex(V, 2) + (-1 * getindex(V, 2)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2))
                        #= none:11 =#
                        ˍ₋out[2] = ((-1 * params.a₂ + (getindex(V, 1) + getindex(V, 1) * log(getindex(X, 2))) / ((2 * getindex(X, 1)) * getindex(X, 2))) + (-1 * params.b₂) / getindex(X, 2)) + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2) ^ 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), u = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd20c7564, 0xd9f14488, 0x7c9632d0, 0x567848cf, 0x0ce88cdb), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(V, 1)
                        #= none:11 =#
                        ˍ₋out[2] = getindex(V, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), g = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x20813b47, 0x473ac96b, 0x125c3108, 0x71639974, 0x81831468), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1) ^ 2) * getindex(X, 2)) + (-1 * getindex(V, 2) + (-1 * getindex(V, 2)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2))
                        #= none:11 =#
                        ˍ₋out[2] = (getindex(V, 1) + getindex(V, 1) * log(getindex(X, 2))) / ((2 * getindex(X, 1)) * getindex(X, 2)) + (((-1 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + (getindex(V, 2) * getindex(X, 1)) * log(getindex(X, 1))) / ((2 * getindex(X, 1)) * getindex(X, 2) ^ 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ū = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xd20c7564, 0xd9f14488, 0x7c9632d0, 0x567848cf, 0x0ce88cdb), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(V, 1)
                        #= none:11 =#
                        ˍ₋out[2] = getindex(V, 2)
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ḡ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe5f4d276, 0x24c3195f, 0x52977c34, 0xb7208624, 0xe37a73af), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(V, 2) / ((2 * getindex(X, 1)) * getindex(X, 2)) + ((-1 * getindex(V, 1)) * log(getindex(X, 2))) / (2 * getindex(X, 1) ^ 2)
                        #= none:11 =#
                        ˍ₋out[2] = (getindex(V, 2) * log(getindex(X, 1))) / (2 * getindex(X, 2) ^ 2) + (-1 * getindex(V, 1)) / ((2 * getindex(X, 1)) * getindex(X, 2))
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), p = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe9912e1f, 0xebb1dd3e, 0x53c1640c, 0x7293ae55, 0x7aada184), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                begin
                    #= none:10 =#
                    SymbolicUtils.Code.create_array(Array, nothing, Val{1}(), Val{(2,)}(), log(getindex(X, 2)) / (2 * getindex(X, 1)), (-1 * log(getindex(X, 1))) / (2 * getindex(X, 2)))
                end
            end
        end
end), ϑ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xf311f19d, 0xc8b557ea, 0xc98bcd8a, 0xe5ab0856, 0x025e67e8), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = log(getindex(X, 2)) / (2 * getindex(X, 1))
                        #= none:11 =#
                        ˍ₋out[2] = (-1 * log(getindex(X, 1))) / (2 * getindex(X, 2))
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ω = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x6e2eecfa, 0x18781c0d, 0xabb45a2a, 0xeb27d0b1, 0x1a280cff), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = 0
                        #= none:11 =#
                        ˍ₋out[2] = 1 / (getindex(X, 1) * getindex(X, 2))
                        #= none:12 =#
                        ˍ₋out[3] = -1 / (getindex(X, 1) * getindex(X, 2))
                        #= none:13 =#
                        ˍ₋out[4] = 0
                        #= none:15 =#
                        ˍ₋out
                    end
            end
        end
end), ϕ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfefbd262, 0xde882f29, 0x3ed25564, 0x5fcbc742, 0x4908734c), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = getindex(P, 1) + (-1 * log(getindex(X, 2))) / (2 * getindex(X, 1))
                        #= none:11 =#
                        ˍ₋out[2] = getindex(P, 2) + log(getindex(X, 1)) / (2 * getindex(X, 2))
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), ψ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :F, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x83e5ca8d, 0xbf3d8275, 0xe53986f9, 0xfc32d56b, 0x0d923dba), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = (getindex(F, 1) + -1 * (getindex(V, 2) / ((2 * getindex(X, 1)) * getindex(X, 2)))) + -1 * (((-1 * getindex(V, 1)) * log(getindex(X, 2))) / (2 * getindex(X, 1) ^ 2))
                        #= none:11 =#
                        ˍ₋out[2] = (getindex(F, 2) + -1 * ((getindex(V, 2) * log(getindex(X, 1))) / (2 * getindex(X, 2) ^ 2))) + -1 * ((-1 * getindex(V, 1)) / ((2 * getindex(X, 1)) * getindex(X, 2)))
                        #= none:13 =#
                        ˍ₋out
                    end
            end
        end
end), P = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xe4448603, 0x32b58c2a, 0xd43f4eae, 0xcefa934f, 0xef815687), Expr}(quote
    #= none:1 =#
    #= none:2 =#
    #= none:2 =# @inbounds begin
            #= none:4 =#
            begin
                #= none:8 =#
                #= none:8 =# @inbounds begin
                        #= none:10 =#
                        ˍ₋out[1] = 0
                        #= none:11 =#
                        ˍ₋out[2] = (-1 * getindex(X, 1)) * getindex(X, 2)
                        #= none:12 =#
                        ˍ₋out[3] = getindex(X, 1) * getindex(X, 2)
                        #= none:13 =#
                        ˍ₋out[4] = 0
                        #= none:15 =#
                        ˍ₋out
                    end
            end
        end
end))),)

 Timespan: (0.0, 10.0) 
 Timestep: 0.01 

 Initial conditions: 
   (t = fill(0.0), q = [2.0, 1.0], p = [0.0, -0.34657359027997264], v = [2.0, 1.0])

 Parameters: 
   (a₁ = -1.0, a₂ = -1.0, b₁ = 1.0, b₂ = 2.0)

We can integrate this system using GeometricIntegrators:

using GeometricIntegrators
sol = integrate(lprob, Gauss(1))

using CairoMakie
fig = lines(parent(sol.q[:,1]), parent(sol.q[:,2]);
    axis = (; xlabel = "x₁", ylabel = "x₂", title = "Lotka-Volterra system in 2d"),
    figure = (; size = (800,600), fontsize = 22))