Skip to main contentfinslerax

From installation to first solve

Get started

The distribution and import are both named finslerax; the examples abbreviate it to fax. The core installation contains the geometry, solvers and learning utilities, with plotting kept in an optional extra.

Install

Python 3.10 or later. Install the stable release from PyPI; this site is built against the matching v1.1.0 source tag.

bash

pip install finslerax

To work on the library itself, clone it and install in place. The extras are additive on top of the core:

bash

git clone https://github.com/hubibala/finslerax.git
cd finslerax
pip install -e ".[dev]"    # + pytest, ruff, mypy, matplotlib, plotly, jupyter
pip install -e ".[viz]"    # + matplotlib and plotly, for finslerax.vis

Check which release is imported with:

bash

python -c "import finslerax; print(finslerax.__version__)"

The gpu extra installs jax[cuda12]. For any other accelerator, follow the JAX installation guide and install finslerax without it, since the JAX build is the part that has to match the hardware.

Domain datasets and application-specific dependencies are deliberately outside the distribution, so installing the framework pulls in only the geometry, solver, and learning stack documented here.

Precision

Floating-point precision follows JAX’s jax_enable_x64 flag; finslerax does not maintain a second precision setting. JAX disables 64-bit array types by default. Set the flag before importing code that creates arrays, either through the environment as below or with jax.config.update("jax_enable_x64", True)early in the process. Integer, Boolean and explicitly requested dtypes still follow JAX’s normal dtype rules.

bash

JAX_ENABLE_X64=1 python your_script.py

The test suite exercises both precision modes on every commit.

What is cheap and what is not

A spray evaluation differentiates the energy twice. The eikonal solvers use repeated sweeps in the forward pass and an implicit adjoint at the converged fixed point, so their backward-pass memory does not grow with the sweep count.

Curvature is more expensive. The full pipeline reaches fourth-order automatic differentiation of the energy, its intermediate Jacobians scale as O(D4)O(D^4), and XLA compilation can take several minutes at D≥8D \geq 8. Wrap it in jax.jit once and reuse the compiled function rather than calling it in a loop; it is an instrument for analysis rather than a routine inner-loop training quantity. Near a degenerate metric, it also amplifies the regularisation already present in the spray.

First geodesic

A minimal script creates a domain, defines the cost metric, and solves a boundary-value problem. We will use a Randers metric, which describes a Riemannian space with an added drift field (like a boat in a river).

python

import finslerax as fax
import jax.numpy as jnp

# A flat 2D space, with a steady eastward wind at 30% of the craft's own speed.
metric = fax.Randers(fax.EuclideanSpace(dim=2),
                     h_net=lambda x: jnp.eye(2),
                     w_net=lambda x: jnp.array([0.3, 0.0]))

# Solve for the shortest path from the origin to (1, 1).
# We use the Accelerated Variational Boundary-value Descent (AVBD) solver.
traj = fax.AVBDSolver(iterations=50).solve(
    metric, jnp.array([0., 0.]), jnp.array([1., 1.]), n_steps=20)

# Calculate the actual asymmetric path cost.
print(metric.arc_length(traj.xs))        # 1.1890  (downwind, cheaper)
print(metric.arc_length(traj.xs[::-1]))  # 1.8484  (upwind, more expensive)

Reversing these waypoints changes the cost because this Randers metric is not reversible. The Randers and Zermelo page derives the metric and states the bound on its drift.