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 = ((1//2)*(v(t))[1]*(x(t))[2]*log((x(t))[2]) - (1//2)*(v(t))[2]*(x(t))[1]*log((x(t))[1])) / ((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", (0x2b6796c5, 0xc7038f1c, 0x05aaa4f2, 0xa7a37a31, 0xb6170ee9), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = (1 // 2 * log(getindex(X, 2))) / getindex(X, 1)
                #= none:10 =#
                ˍ₋out[2] = (-1 // 2 * log(getindex(X, 1))) / getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end)
   f = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xad437f9d, 0xbc3e83f1, 0x0fcc84bd, 0xc003e345, 0x864d5cf8), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = ((-1 * params.a₁ + (-1 // 2 * getindex(V, 2) + (-1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2))) + (-1 * params.b₁) / getindex(X, 1)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) ^ 2 * getindex(X, 2))
                #= none:10 =#
                ˍ₋out[2] = ((-1 * params.a₂ + (-1 * params.b₂) / getindex(X, 2)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2) ^ 2)) + (1 // 2 * getindex(V, 1) + (1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / (getindex(X, 1) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end)
   g = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xc952f36d, 0x0b3274a1, 0x5a98bf60, 0x2329f298, 0x8174cb0d), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = (-1 // 2 * getindex(V, 2) + (-1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) ^ 2 * getindex(X, 2))
                #= none:10 =#
                ˍ₋out[2] = (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2) ^ 2) + (1 // 2 * getindex(V, 1) + (1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / (getindex(X, 1) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end)

 Lagrangian: L = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfc4f47a4, 0x4fbe2d9e, 0x542e7e9b, 0xc4e07e8e, 0x44c0c820), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    ((((((1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((-1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (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)

 Invariants: 
   (h = EulerLagrange.var"#90#91"{@NamedTuple{L::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfc4f47a4, 0x4fbe2d9e, 0x542e7e9b, 0xc4e07e8e, 0x44c0c820), Expr}, H::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x1fd90528, 0xad128186, 0xac9fbe57, 0xcaac718b, 0xf104b744), Expr}, EL::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xbfa88298, 0xe4eeac6c, 0x6282c223, 0x0f2d42df, 0x0be87f06), Expr}, ∇H::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xb02a312d, 0xdcc8f664, 0x77fea323, 0x3c6e1dcf, 0x85143e8a), Expr}, ẋ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcd1ffa8c, 0xc4441362, 0xe0f83747, 0x1beb287f, 0xa154b416), Expr}, v::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcd1ffa8c, 0xc4441362, 0xe0f83747, 0x1beb287f, 0xa154b416), Expr}, f::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xad437f9d, 0xbc3e83f1, 0x0fcc84bd, 0xc003e345, 0x864d5cf8), Expr}, u::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9074dbae, 0x9dbd5857, 0x29f62319, 0xac7fc940, 0x64f9e588), Expr}, g::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xc952f36d, 0x0b3274a1, 0x5a98bf60, 0x2329f298, 0x8174cb0d), Expr}, ū::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9074dbae, 0x9dbd5857, 0x29f62319, 0xac7fc940, 0x64f9e588), Expr}, ḡ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x5dd8f1c1, 0x64ee23ef, 0x65d6e415, 0x93a2dcf0, 0xc9116c7a), Expr}, p::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xdeb1e969, 0x01b4695d, 0x35148672, 0xdc0212d8, 0xfddd0261), Expr}, ϑ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x2b6796c5, 0xc7038f1c, 0x05aaa4f2, 0xa7a37a31, 0xb6170ee9), Expr}, ω::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9f1dd65e, 0xe98e31d6, 0xc077f403, 0xbf1d9b2a, 0xfdcf4fcd), Expr}, ϕ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x5fc08be0, 0x9d1c6478, 0x1fc693e6, 0x049c9ff7, 0x07f82e11), Expr}, ψ::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :F, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x1385c301, 0x477bd586, 0x5d26ff37, 0xfad84fef, 0x150de6c6), Expr}, P::RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xb3beb4ec, 0x1199f700, 0x9e11c355, 0x025bf187, 0xfd792d21), Expr}}}((L = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xfc4f47a4, 0x4fbe2d9e, 0x542e7e9b, 0xc4e07e8e, 0x44c0c820), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    ((((((1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((-1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (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), H = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x1fd90528, 0xad128186, 0xac9fbe57, 0xcaac718b, 0xf104b744), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    ((getindex(X, 1) * params.a₁ + getindex(X, 2) * params.a₂) + params.b₁ * log(getindex(X, 1))) + params.b₂ * log(getindex(X, 2))
end), EL = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xbfa88298, 0xe4eeac6c, 0x6282c223, 0x0f2d42df, 0x0be87f06), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = -1 * params.a₁ + (-1 * params.b₁) / getindex(X, 1)
                #= none:10 =#
                ˍ₋out[2] = -1 * params.a₂ + (-1 * params.b₂) / getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), ∇H = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xb02a312d, 0xdcc8f664, 0x77fea323, 0x3c6e1dcf, 0x85143e8a), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = params.a₁ + params.b₁ / getindex(X, 1)
                #= none:10 =#
                ˍ₋out[2] = params.a₂ + params.b₂ / getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), ẋ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcd1ffa8c, 0xc4441362, 0xe0f83747, 0x1beb287f, 0xa154b416), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(X, 1) * (params.b₂ + getindex(X, 2) * params.a₂)
                #= none:10 =#
                ˍ₋out[2] = (-1 * (params.b₁ + getindex(X, 1) * params.a₁)) * getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), v = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xcd1ffa8c, 0xc4441362, 0xe0f83747, 0x1beb287f, 0xa154b416), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(X, 1) * (params.b₂ + getindex(X, 2) * params.a₂)
                #= none:10 =#
                ˍ₋out[2] = (-1 * (params.b₁ + getindex(X, 1) * params.a₁)) * getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), f = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xad437f9d, 0xbc3e83f1, 0x0fcc84bd, 0xc003e345, 0x864d5cf8), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = ((-1 * params.a₁ + (-1 // 2 * getindex(V, 2) + (-1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2))) + (-1 * params.b₁) / getindex(X, 1)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) ^ 2 * getindex(X, 2))
                #= none:10 =#
                ˍ₋out[2] = ((-1 * params.a₂ + (-1 * params.b₂) / getindex(X, 2)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2) ^ 2)) + (1 // 2 * getindex(V, 1) + (1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / (getindex(X, 1) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end), u = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9074dbae, 0x9dbd5857, 0x29f62319, 0xac7fc940, 0x64f9e588), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(V, 1)
                #= none:10 =#
                ˍ₋out[2] = getindex(V, 2)
                #= none:12 =#
                nothing
            end
    end
end), g = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xc952f36d, 0x0b3274a1, 0x5a98bf60, 0x2329f298, 0x8174cb0d), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = (-1 // 2 * getindex(V, 2) + (-1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2)) + (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) ^ 2 * getindex(X, 2))
                #= none:10 =#
                ˍ₋out[2] = (((-1 // 2 * getindex(V, 1)) * getindex(X, 2)) * log(getindex(X, 2)) + ((1 // 2 * getindex(V, 2)) * getindex(X, 1)) * log(getindex(X, 1))) / (getindex(X, 1) * getindex(X, 2) ^ 2) + (1 // 2 * getindex(V, 1) + (1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / (getindex(X, 1) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end), ū = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9074dbae, 0x9dbd5857, 0x29f62319, 0xac7fc940, 0x64f9e588), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(V, 1)
                #= none:10 =#
                ˍ₋out[2] = getindex(V, 2)
                #= none:12 =#
                nothing
            end
    end
end), ḡ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :Λ, :P, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x5dd8f1c1, 0x64ee23ef, 0x65d6e415, 0x93a2dcf0, 0xc9116c7a), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(V, 2) / ((2 * getindex(X, 1)) * getindex(X, 2)) + ((-1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / getindex(X, 1) ^ 2
                #= none:10 =#
                ˍ₋out[2] = ((1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / getindex(X, 2) ^ 2 + (-1 * getindex(V, 1)) / ((2 * getindex(X, 1)) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end), p = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xdeb1e969, 0x01b4695d, 0x35148672, 0xdc0212d8, 0xfddd0261), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        SymbolicUtils.Code.create_array(Array, nothing, Val{1}(), Val{(2,)}(), (1 // 2 * log(getindex(X, 2))) / getindex(X, 1), (-1 // 2 * log(getindex(X, 1))) / getindex(X, 2))
    end
end), ϑ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x2b6796c5, 0xc7038f1c, 0x05aaa4f2, 0xa7a37a31, 0xb6170ee9), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = (1 // 2 * log(getindex(X, 2))) / getindex(X, 1)
                #= none:10 =#
                ˍ₋out[2] = (-1 // 2 * log(getindex(X, 1))) / getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), ω = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x9f1dd65e, 0xe98e31d6, 0xc077f403, 0xbf1d9b2a, 0xfdcf4fcd), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = 0
                #= none:10 =#
                ˍ₋out[2] = 1 / (getindex(X, 1) * getindex(X, 2))
                #= none:11 =#
                ˍ₋out[3] = -1 / (getindex(X, 1) * getindex(X, 2))
                #= none:12 =#
                ˍ₋out[4] = 0
                #= none:14 =#
                nothing
            end
    end
end), ϕ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x5fc08be0, 0x9d1c6478, 0x1fc693e6, 0x049c9ff7, 0x07f82e11), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = getindex(P, 1) + (-1 // 2 * log(getindex(X, 2))) / getindex(X, 1)
                #= none:10 =#
                ˍ₋out[2] = getindex(P, 2) + (1 // 2 * log(getindex(X, 1))) / getindex(X, 2)
                #= none:12 =#
                nothing
            end
    end
end), ψ = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :P, :F, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0x1385c301, 0x477bd586, 0x5d26ff37, 0xfad84fef, 0x150de6c6), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = (getindex(F, 1) + ((1 // 2 * getindex(V, 1)) * log(getindex(X, 2))) / getindex(X, 1) ^ 2) + (-1 * getindex(V, 2)) / ((2 * getindex(X, 1)) * getindex(X, 2))
                #= none:10 =#
                ˍ₋out[2] = (getindex(F, 2) + ((-1 // 2 * getindex(V, 2)) * log(getindex(X, 1))) / getindex(X, 2) ^ 2) + getindex(V, 1) / ((2 * getindex(X, 1)) * getindex(X, 2))
                #= none:12 =#
                nothing
            end
    end
end), P = RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :t, :X, :V, :params), EulerLagrange.var"#_RGF_ModTag", EulerLagrange.var"#_RGF_ModTag", (0xb3beb4ec, 0x1199f700, 0x9e11c355, 0x025bf187, 0xfd792d21), Expr}(quote
    #= none:1 =#
    #= none:5 =#
    begin
        #= none:7 =#
        #= none:7 =# @inbounds begin
                #= none:9 =#
                ˍ₋out[1] = 0
                #= none:10 =#
                ˍ₋out[2] = (-1 * getindex(X, 1)) * getindex(X, 2)
                #= none:11 =#
                ˍ₋out[3] = getindex(X, 1) * getindex(X, 2)
                #= none:12 =#
                ˍ₋out[4] = 0
                #= none:14 =#
                nothing
            end
    end
end))),)

 Timespan: (0.0, 10.0) 
 Timestep: 0.01 

 Initial conditions: 
   (t = 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))