Elliptic integrals — examples
MeanFieldHom re-exports the five entry points of the MeanFieldHom.Elliptic submodule: ell_K, ell_E, ell_F, ell_RF, ell_RD.
Basic calls
using MeanFieldHom
# Complete integrals, Float64 fast path
m = 0.5
K = ell_K(m)
E = ell_E(m)
(K, E)(1.854074677301372, 1.3506438810476757)# The generic AGM path agrees with the Float64 fast path when promoted
K_big = ell_K(BigFloat(m))
abs(Float64(K_big) - K)2.220446049250313e-16# Incomplete integrals
φ = π/4
F = ell_F(φ, m)
E2 = ell_E(φ, m)
(F, E2)(0.8260178762492452, 0.7481865041776614)Carlson symmetric forms
# Unit-integration identity: R_F(1, 1, 1) = 1
ell_RF(1.0, 1.0, 1.0)1.0# Homogeneity: R_F(λx, λy, λz) = λ^{-1/2} R_F(x, y, z)
λ = 3.0
λ^(-0.5) * ell_RF(1.0, 2.0, 3.0), ell_RF(λ, 2λ, 3λ)(0.41970243152927844, 0.4197024315292785)Automatic differentiation
The elliptic submodule is designed to flow through ForwardDiff. The Float64 fast path is automatically replaced by the generic AGM / Carlson code whenever the input is a ForwardDiff.Dual:
using MeanFieldHom, ForwardDiff
# Derivative of K(m) at m = 0.3
dKdm = ForwardDiff.derivative(ell_K, 0.3)
# Reference value: dK/dm = (E - (1-m)K) / (2m(1-m))
m = 0.3
ref = (ell_E(m) - (1 - m) * ell_K(m)) / (2m * (1 - m))
(dKdm, ref, abs(dKdm - ref))(0.5848582159226465, 0.5848582159226468, 2.220446049250313e-16)# Gradient of a scalar functional involving F(φ, m)
using ForwardDiff: gradient
f(x) = ell_F(x[1], x[2])^2 + ell_E(x[1], x[2])
g = gradient(f, [0.4, 0.5])2-element Vector{Float64}:
1.8046456522416205
-0.0015838344680385221Arbitrary precision
Using BigFloat gives access to the full precision of the AGM recursion:
using MeanFieldHom
setprecision(BigFloat, 128) # 128 mantissa bits
m = BigFloat("0.25")
K_big = ell_K(m)
K_f64 = ell_K(Float64(m))
# Round-trip error (BigFloat → Float64)
abs(Float64(K_big) - K_f64)2.220446049250313e-16Symbolic computation
With the optional SymPy extension loaded (the package declares SymPy as a [weakdeps]), the complete integrals become symbolic closed-form expressions:
using MeanFieldHom, SymPy
@syms m
ell_K(m) # → K(m) as a SymPy expression
ell_E(π/4, m) # → SymPy elliptic_e(π/4, m)With Symbolics (no extension required — the pure-arithmetic AGM path is used):
using MeanFieldHom, Symbolics
@variables m
expr = ell_K(m)
# Symbolics expression — use `simplify(expr)` to compact the output.Custom scalar backends
Adding a new backend for a user-defined Number type amounts to adding methods on the public API:
struct MyScalar <: Number
x::Float64
end
Base.float(s::MyScalar) = s.x
# Route K and E through the fast Float64 path
MeanFieldHom.Elliptic.ell_K(s::MyScalar) = ell_K(s.x)
MeanFieldHom.Elliptic.ell_E(s::MyScalar) = ell_E(s.x)Downstream code that calls ell_K, ell_E, ell_F, ell_RF, ell_RD will pick up the new methods automatically — multiple dispatch does the rest.