Metadata-Version: 2.4
Name: gri-ell
Version: 0.2.0
Project-URL: repository, https://gitlab.com/geosol-foss/python/gri-ell
Project-URL: homepage, https://geosolresearch.com
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.14
Requires-Dist: gri-memoize
Requires-Dist: gri-pos
Requires-Dist: gri-utils
Requires-Dist: numpy>=2.3.3
Requires-Dist: scipy>=1.16.2
Description-Content-Type: text/markdown

[![GeoSol Research Logo](https://geosolresearch.com/logos/foss_logo.png "GeoSol Research")](https://geosolresearch.com)

# Ell (Ellipsoid Statistics)

Statistical ellipsoid and ellipse representations with lazy-loaded coordinate conversions and Mahalanobis distance calculations.

## Overview

gri-ell provides the `Ell` class, which pairs a geodetic position (inherited from `Pos`) with a statistical uncertainty region -- an ellipsoid in 3D or ellipse in 2D. Internally, `Ell` can store covariance matrices, information matrices, or 2D ellipse parameters, and lazily converts between them as needed.

The primary use cases are geolocation error analysis, ellipsoid convolution (via gri-convolve), and statistical distance calculations between position estimates.

Requires Python 3.14+.

## Mathematical Background

**Covariance and information matrices.** An `Ell` object encapsulates two dual representations of the same uncertainty:

- Covariance matrix `C` (ENU coordinates, m^2, 1-sigma): describes spread of the position estimate
- Information matrix `I = R C^{-1} R^T` (XYZ coordinates, 1/m^2, 1-sigma): the inverse covariance rotated into ECEF, used in fusion algorithms

where `R` is the ENU-to-XYZ rotation matrix at the position.

**2D ellipse.** The 2D ellipse is the East-North projection of the 3D ellipsoid, parameterized by semi-major axis (SMA), semi-minor axis (SMI), orientation angle (degrees clockwise from North), and altitude uncertainty. Ellipse parameters are reported at 95% confidence.

**Mahalanobis distance.** The statistical distance from a point `x` to an ellipsoid centered at `mu` with information matrix `I`:

    d_M = sqrt((x - mu)^T I (x - mu))

This is unitless: 0 at the center, 1 on the ellipsoid surface, 2 at twice the ellipsoid boundary. It generalizes Euclidean distance to account for the shape and orientation of the uncertainty region.

**Norm distance.** Mahalanobis distance scaled to 95% confidence intervals by dividing by `sqrt(SIG_TO_95)`. After scaling, a norm distance of 1.0 means the point lies on the 95% confidence boundary.

Scaling factors from the chi-squared distribution:

| Dimension | 1-sigma to 95% scale factor |
|-----------|---------------------------|
| 1D        | 1.96                       |
| 2D        | 2.448                      |
| 3D        | 2.796                      |

Reference: Mahalanobis, P.C. (1936). "On the generalized distance in statistics."

## Installation

```bash
pip install gri-ell
```

For development:

```bash
git clone https://gitlab.com/geosol-foss/python/gri-ell.git
cd gri-ell
. .init_venv.sh
```

## Quick Start

```python
from gri_ell import Ell
from gri_pos import Pos

# Create from 2D ellipse parameters (SMA, SMI, orientation in deg, all 95%)
ell = Ell.from_2d(Pos.LLA(40.0, -105.0, 1600), sma_95_m=100, smi_95_m=50, ori_deg=45)

# Access ellipse properties
print(ell.ellipse.sma_95)   # 100.0 (semi-major axis, meters, 95%)
print(ell.ellipse.smi_95)   # 50.0
print(ell.ellipse.ori_deg)  # 45.0 (degrees clockwise from North)

# Statistical distance to another point
other = Pos.LLA(40.001, -105.001, 1610)
d = ell.dist_norm(other)    # Normalized 95% distance
print(f"Norm distance: {d:.2f}")
```

## Creating Ell Objects

`Ell` provides several static constructors. Choose based on what data you have:

| Constructor | Input format | When to use |
|-------------|-------------|-------------|
| `Ell.from_2d(pos, sma, smi, ori, alt)` | SMA/SMI/ORI at 95% | Human-readable ellipse parameters |
| `Ell.COV(pos, matrix)` | 3x3 ENU, m^2, 1-sigma | Raw covariance from a filter or estimator |
| `Ell.CONF(pos, matrix)` | 3x3 ENU, m^2, 95% | Pre-scaled 95% confidence matrix |
| `Ell.INFO(pos, matrix)` | 3x3 XYZ, 1/m^2, 1-sigma | Information matrix from fusion algorithms |
| `Ell.Ellipse(pos, matrix)` | 2x2 EN, m^2, 1-sigma | 2D covariance matrix directly |

```python
import numpy as np

# From 2D parameters (most common)
ell = Ell.from_2d(pos, sma_95_m=100, smi_95_m=50, ori_deg=45)

# From a 3x3 covariance matrix (ENU, m^2, 1-sigma)
cov = np.array([[100, 10, 0], [10, 50, 0], [0, 0, 25]])
ell = Ell.COV(pos, cov)

# From an information matrix (XYZ, 1/m^2, 1-sigma)
info = np.linalg.inv(cov_xyz)
ell = Ell.INFO(pos, info)
```

## Matrix Representations

Each `Ell` stores one representation and lazily computes the others on first access:

| Property | Coordinates | Units | Scale | Shape |
|----------|------------|-------|-------|-------|
| `ell.cov` | ENU | m^2 | 1-sigma | 3x3 |
| `ell.conf` | ENU | m^2 | 95% | 3x3 |
| `ell.info` | XYZ (ECEF) | 1/m^2 | 1-sigma | 3x3 |
| `ell.ellipse` | East-North | m (95%) | 95% | 2D projection |

The `Ellipse` object provides the 2D parameters directly:

```python
ell.ellipse.sma_95    # Semi-major axis (meters, 95%)
ell.ellipse.smi_95    # Semi-minor axis (meters, 95%)
ell.ellipse.ori_deg   # Orientation (degrees CW from North)
ell.ellipse.alt_95    # Altitude uncertainty (meters, 95%)
ell.ellipse.ori_rad   # Orientation in radians
```

## Statistical Distances

All distance methods return unitless values: 0 at center, 1 on the boundary, >1 outside.

```python
# 3D Mahalanobis distance (sigma units)
d = ell.dist_mahalanobis(other_pos)

# 3D normalized distance (95% confidence units)
d = ell.dist_norm(other_pos)

# 2D variants (East-North projection only, faster but less precise)
d = ell.dist_mahalanobis_2d(other_pos)
d = ell.dist_norm_2d(other_pos)

# Combined distance: accounts for uncertainty of both ellipsoids
d = ell.dist_norm(other_ell, combined=True)
```

## Dependencies

- **gri-memoize**: Per-instance caching of lazy-loaded matrix conversions
- **gri-pos**: Position class (`Pos`) that `Ell` inherits from
- **gri-utils**: Coordinate conversions, constants, ellipsoid math
- **numpy**: Matrix operations


## Other Projects

Current list of other [GRI FOSS Projects](.docs_other_projects.md) we are building and maintaining.

## License

MIT License. See [LICENSE](LICENSE) for details.
