Metadata-Version: 2.4
Name: lmoments-uq
Version: 1.2.0
Summary: L-moments based uncertainty quantification from scarce samples including extremes
Author: Deepan Jayaraman, Palaniappan Ramu
Maintainer-email: Deepan Jayaraman <deepanjayram@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/DeepanJayaraman/L-UQ
Project-URL: Repository, https://github.com/DeepanJayaraman/L-UQ
Project-URL: Changelog, https://github.com/DeepanJayaraman/L-UQ/blob/main/CHANGELOG.md
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.24
Requires-Dist: scipy>=1.10
Provides-Extra: ui
Requires-Dist: streamlit>=1.30; extra == "ui"
Requires-Dist: matplotlib>=3.7; extra == "ui"
Requires-Dist: pandas>=2.0; extra == "ui"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"

# L-moments UQ — Python port

A Python port of the [L-UQ MATLAB toolbox](../README.md) one directory
up: distribution-independent uncertainty quantification from scarce
samples, including data with extremes, using L-moments. Same method,
same 9 supported distribution families, plus an interactive Streamlit
UI.

**Validation.** Every parameter-estimation formula and
distribution-parameterization/sign convention is validated against
known `scipy.stats` ground truth — see
[`tests/test_lmoments.py`](tests/test_lmoments.py) (30 tests). In
addition, this port and the MATLAB implementation have been verified
equivalent: on fixed reference samples, MATLAB's `lmom`,
`Parameter_estimation`, and `CDF_l` reproduce this package's
L-moments, parameter vectors, and fitted CDF values to within 1e-8
(run [`tests/octave_verify.m`](../tests/octave_verify.m) under GNU
Octave, or the MATLAB suite `tests/test_uq_matlab.m` — both pass, the
latter under MATLAB R2026a). On the same samples the package agrees
with R's `lmom` to machine precision wherever the closed forms
coincide.

## Install

```bash
cd python
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[ui,dev]"
```

## Run the tests

```bash
pytest tests/ -v
```

## Run the illustrative example

```bash
python demo_example.py --no-show   # saves demo_example_output.png
```

## Run the interactive UI

```bash
streamlit run app.py
```

Lets you paste in a sample (or generate a synthetic scarce+extreme one),
see its L-moments and the ranked distribution-family match, pick a family
to fit, and view the PDF/CDF fit against the sample compared with a
conventional-moment (MLE) fit of the same family, plus Jensen-Shannon
divergence numbers quantifying the difference.

## Install

```bash
pip install lmoments-uq          # distribution name (hyphen)
```

The import namespace is `lmoments_uq` (underscore), distinct from the
unrelated `lmoments` / `lmoments3` packages on PyPI.

## API

```python
from lmoments_uq import identify_dist, parameter_estimation, pdf_l, cdf_l, random_l, js_div

result = identify_dist(x)              # {'best', 'ranking', 'L_sample'}
params = parameter_estimation(x, result['best'], *result['L_sample'])
pdf_vals = pdf_l(xgrid, result['best'], params)

# uncertainty-aware identification (bootstrap selection frequencies)
from lmoments_uq import identify_dist_bootstrap
boot = identify_dist_bootstrap(x)      # {'best','selection_frequencies','status',...}
```

## Differences from the MATLAB version

- `identify_dist` returns the full ranked distance to **all 9** candidate
  families (`result['ranking']`), not just the single closest match — a
  strict addition, useful for the UI's ranking table.
- `parameter_identify(x, k)` genuinely fits the top-`k` candidates; the
  MATLAB version's `K` argument silently breaks for `K>1` because
  `Identify_dist.m` never actually returns more than one candidate.
- The Gamma distribution's location shift is applied consistently in both
  `pdf_l` and `cdf_l` in both implementations (MATLAB's `CDF_l.m`
  historically omitted it; fixed as of the SoftwareX/JSS submission
  preparation).
- `kl_div(p, q)` returns `inf` when `p` has mass in a bin where `q` has
  none (the mathematically correct value); MATLAB's `KLDiv.m` drops such
  bins and can return a finite — even negative — divergence there. This
  cannot affect `js_div`, whose mixture term is positive wherever `p` is,
  and `js_div` was verified to machine precision against
  `scipy.spatial.distance.jensenshannon` (see the divergence tests).
- `weibul` is supported in `parameter_estimation`/`pdf_l`/`cdf_l`/`random_l`
  for completeness, but — matching the MATLAB version — is not one of the
  families `identify_dist` will pick automatically.

## Known limitations (inherited from the method/toolbox)

- Weibull is not offered for automatic identification (see above).
- Gumbel is the k=0 special case of the GEV curve, and Uniform is the k=1
  boundary case of the GP curve, on the L-moment ratio diagram; for
  samples near those special cases, `identify_dist` can pick either the
  special-case family or its generalizing family. This is a property of
  the diagram itself, not a bug (see `tests/test_lmoments.py` for how this
  is handled in testing).
