orbix.equations.lambert
=======================

.. py:module:: orbix.equations.lambert

.. autoapi-nested-parse::

   Lambert boundary-value problem: elliptic, multi-revolution, differentiable.

   Given two position vectors and the time of flight between them, solve for
   the terminal velocities of the connecting Keplerian orbit. This is the
   classical Lambert *boundary-value* problem (Lancaster & Blanchard 1969;
   Battin 1999, ch. 7; Izzo 2015), distinct from the Lambertian scattering
   phase function in ``orbix.equations.phase``.

   The transfer is parameterized by ``x = cos(alpha/2)`` on the open interval
   ``(-1, 1)``, where ``alpha`` is the Lagrange angle: the semi-major axis is
   ``a = s / (2 (1 - x^2))``, both classical alpha branches collapse into the
   sign of ``x``, and the time of flight ``T(x)`` is strictly decreasing for
   ``N = 0`` and U-shaped (two roots per achievable TOF) for ``N >= 1``
   revolutions. Roots are bracketed by a fixed-iteration ternary search for
   the TOF minimum, then bisected, then polished with Newton steps that carry
   implicit-function-theorem gradients (the bracketing itself runs under
   ``stop_gradient``).

   Every solution family is indexed by three discrete choices:

   - ``N``: number of complete revolutions on the arc.
   - ``long_way``: transfer angle above pi (opposite orbit normal).
   - ``high_branch``: for ``N >= 1``, the larger-x (larger period) of the two
     roots; flagged invalid for ``N = 0``.

   Units are any consistent set (orbix convention: AU, days, and
   ``mu = G * Ms_kg`` in AU^3/day^2). All functions are scalar-core: ``vmap``
   over batches of positions, times, ``N``, or branch flags.

   Degenerate geometries: transfer angles of exactly 0 or pi leave the orbit
   plane undefined and the returned velocities blow up there; callers sample
   past these measure-zero configurations.



Attributes
----------

.. autoapisummary::

   orbix.equations.lambert._X_EPS
   orbix.equations.lambert._DTOF_FLOOR


Functions
---------

.. autoapisummary::

   orbix.equations.lambert._geometry
   orbix.equations.lambert._tof_of_x
   orbix.equations.lambert._tof_argmin_x
   orbix.equations.lambert._bisect_x
   orbix.equations.lambert._newton_polish
   orbix.equations.lambert._terminal_velocities
   orbix.equations.lambert.lambert_solve
   orbix.equations.lambert.lambert_tof_min


Module Contents
---------------

.. py:data:: _X_EPS
   :value: 1e-09


.. py:data:: _DTOF_FLOOR
   :value: 1e-30


.. py:function:: _geometry(r1, r2, long_way)

   Chord/semi-perimeter geometry shared by every Lambert routine.

   :param r1: First position vector, shape ``(3,)``.
   :param r2: Second position vector, shape ``(3,)``.
   :param long_way: Whether the transfer angle exceeds pi.

   :returns: the two radii, chord length,
             semi-perimeter, and the signed Lambert parameter
             ``lam = +/- sqrt((s - c) / s)`` (negative on the long way).
   :rtype: Tuple ``(r1n, r2n, c, s, lam)``


.. py:function:: _tof_of_x(x, s, lam, mu, N)

   Elliptic Lagrange time of flight at ``x = cos(alpha/2)``.

   ``alpha = 2 arccos(x)`` spans ``(0, 2 pi)`` as ``x`` spans ``(-1, 1)``,
   so both classical alpha branches are covered without a flag;
   ``beta = 2 arcsin(lam sqrt(1 - x^2))`` carries the transfer-way sign
   through ``lam``.


.. py:function:: _tof_argmin_x(s, lam, mu, N, iters)

   Locate the x minimizing ``T(x)`` via fixed-iteration ternary search.

   For ``N >= 1`` the minimum is interior (the double-root point); for
   ``N = 0``, where ``T`` is strictly decreasing, the search converges to
   the upper domain edge, whose TOF is the near-parabolic elliptic
   infimum. Runs on values only -- callers wrap in ``stop_gradient``.


.. py:function:: _bisect_x(tof, s, lam, mu, N, lo, hi, iters)

   Bisection root of ``T(x) = tof`` on a monotone bracket ``[lo, hi]``.


.. py:function:: _newton_polish(x, tof, s, lam, mu, N, steps)

   Differentiable Newton refinement of a gradient-stopped root.

   Refines ``T(x) = tof`` and, because the incoming ``x`` carries no
   gradients, attaches the implicit-function gradients of the root to
   every upstream input.


.. py:function:: _terminal_velocities(r1, r2, x, s, lam, mu, long_way, r1n, r2n, c)

   Terminal velocities from the converged ``x`` via Lagrange f and g.


.. py:function:: lambert_solve(r1, r2, tof, mu, N=0, long_way=False, high_branch=False, *, bisect_iters = 64, ternary_iters = 104, polish_steps = 2)

   Solve the elliptic Lambert problem for one ``(N, way, branch)`` family.

   :param r1: Position at the first epoch, shape ``(3,)``.
   :param r2: Position at the second epoch, shape ``(3,)``.
   :param tof: Time of flight between the epochs (same units as ``mu``).
   :param mu: Gravitational parameter ``G * M``.
   :param N: Complete revolutions on the arc (int, traceable).
   :param long_way: Transfer angle above pi (flips the orbit normal).
   :param high_branch: For ``N >= 1``, select the larger-x of the two roots.
                       No high branch exists for ``N = 0`` (flagged invalid).
   :param bisect_iters: Fixed bisection iterations (static).
   :param ternary_iters: Fixed ternary-search iterations for the TOF
                         minimum used to bracket and to test existence (static).
   :param polish_steps: Differentiable Newton refinements (static); these
                        carry the implicit-function gradients of the solution.

   :returns: Velocity at ``r1``, shape ``(3,)``.
             v2: Velocity at ``r2``, shape ``(3,)``.
             valid: Boolean; False when no elliptic solution exists for this
                 ``(N, long_way, high_branch)`` family (outputs are then
                 meaningless and must be masked by the caller).
   :rtype: v1


.. py:function:: lambert_tof_min(r1, r2, mu, N=0, long_way=False, *, ternary_iters = 104)

   Minimum elliptic time of flight for an ``N``-revolution transfer.

   For ``N >= 1`` this is the TOF at the double-root point (solutions
   exist iff ``tof >= lambert_tof_min``); for ``N = 0`` it is the
   near-parabolic infimum of the elliptic family. Gradients are correct
   at interior minima by the envelope theorem.

   :param r1: Position at the first epoch, shape ``(3,)``.
   :param r2: Position at the second epoch, shape ``(3,)``.
   :param mu: Gravitational parameter ``G * M``.
   :param N: Complete revolutions on the arc (int, traceable).
   :param long_way: Transfer angle above pi.
   :param ternary_iters: Fixed ternary-search iterations (static).

   :returns: The minimum time of flight (same units as ``mu``).


