Metadata-Version: 2.5
Name: max-div
Version: 0.15.0
Summary: Configurable Solver for Maximum Diversity Problems with Fairness Constraints.
Project-URL: Documentation, https://max-div.readthedocs.io/
Project-URL: Source, https://github.com/bertpl/max-div
Project-URL: ChangeLog, https://github.com/bertpl/max-div/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/bertpl/max-div/issues
Project-URL: Roadmap, https://github.com/bertpl/max-div/milestones
Author: Bert Pluymers
License-Expression: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: click>=8.2.0
Requires-Dist: icc-rt; platform_machine == 'x86_64' and platform_system == 'Linux'
Requires-Dist: intel-cmplr-lib-rt; platform_machine == 'x86_64' and platform_system == 'Linux'
Requires-Dist: numba>=0.57; python_version < '3.12'
Requires-Dist: numba>=0.59; python_version == '3.12'
Requires-Dist: numba>=0.61; python_version == '3.13'
Requires-Dist: numba>=0.63; python_version >= '3.14'
Requires-Dist: numpy>=2.0.0; python_version < '3.13'
Requires-Dist: numpy>=2.1.0; python_version == '3.13'
Requires-Dist: numpy>=2.3.2; python_version >= '3.14'
Requires-Dist: scipy>=1.10.0; python_version < '3.13'
Requires-Dist: scipy>=1.14.1; python_version == '3.13'
Requires-Dist: scipy>=1.16.1; python_version >= '3.14'
Requires-Dist: tqdm>=4.66.0
Description-Content-Type: text/markdown

[![CI](https://img.shields.io/github/actions/workflow/status/bertpl/max-div/push_to_main.yml?branch=main&label=CI)](https://github.com/bertpl/max-div/actions/workflows/push_to_main.yml)
![coverage](https://img.shields.io/badge/coverage-99.38%25-brightgreen)
![tests](https://img.shields.io/badge/tests-4553-blue)
[![docs-build-status](https://app.readthedocs.org/projects/max-div/badge/?version=latest)](https://max-div.readthedocs.io/en/stable)
[![PyPI](https://img.shields.io/pypi/v/max-div.svg)](https://pypi.org/project/max-div/)
[![Python](https://img.shields.io/pypi/pyversions/max-div.svg)](https://pypi.org/project/max-div/)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue)](https://github.com/bertpl/max-div/blob/main/LICENSE)
[![code style: ruff](https://img.shields.io/badge/code%20style-ruff-261230)](https://github.com/astral-sh/ruff)
[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/bertpl/max-div/badge)](https://scorecard.dev/viewer/?uri=github.com/bertpl/max-div)
<p align="center">
  <img src="https://raw.githubusercontent.com/bertpl/max-div/v0.15.0/images/splash_with_version.webp" alt="max-div logo" style="max-width: max(60%, min(100%,900px)); height: auto;">
</p>

# max-div

**A versatile, high-performance solver for Maximum Diversity Problems** — select the `k` most
diverse of `n` items, under optional fairness constraints.

## Highlights

- ⚡ obtains **near-optimal results within seconds-to-one-minute** for problems up to `n=200k`

- 🚀 leverages [numba](https://pypi.org/project/numba/) **JIT-compilation for maximum speed** without relying on pre-compiled binaries

- ⚖️ natively supports flexible **fairness constraints**

  - uniquely supports **constraints with overlapping sets & ranged counts**

  - returns the **least infeasible solution** (with configurable weighted linear or quadratic penalties) when constraints conflict

  - provides **proofs of (in)feasibility**

- 📐 uniquely supports **5+ distance metrics** (L1, L2, L∞, Minkowski, cosine — or precomputed distances) and **4 diversity metrics** (minimum, mean & geomean separation + mean pairwise distance) in any combination

- 💾 computes item distances **eagerly when memory allows** (maximum speed), **lazily when problem size requires** (minimal memory usage)

- 🤝 leverages multi-core CPUs with **parallel workers** in independent, cooperative or dynamically grouped configurations, **without duplicating core problem data**

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/bertpl/max-div/v0.15.0/docs/images/hero_dark.svg">
    <img src="https://raw.githubusercontent.com/bertpl/max-div/v0.15.0/docs/images/hero_light.svg" alt="Feature comparison of max-div against exact solvers and one-shot pickers: distance metrics, diversity objectives, constraint handling, time budgets and practical scale" style="max-width: max(60%, min(100%,1000px)); height: auto;">
  </picture>
</p>

The [benchmarks](https://max-div.readthedocs.io/en/stable/benchmarks/comparison/overview/)
compare max-div in depth with 10 other freely available solvers.

## Installation

```bash
pip install max-div
```

Python 3.11+; free-threaded builds (3.14t) are supported and CI-tested (see the
[installation notes](https://max-div.readthedocs.io/en/stable/getting_started/#installation) for
the numba version they require).

## Quick start

```python
import numpy as np
from max_div import MaxDivProblem, MaxDivSolverBuilder, seconds

rng = np.random.default_rng(42)
vectors = rng.random((200, 5))               # 200 points in 5 dimensions

# select the 20 most diverse, improving for up to 5 seconds
problem = MaxDivProblem.new(vectors, k=20)
solution = MaxDivSolverBuilder(problem).with_preset(seconds(5)).build().solve()

print(solution.i_selected)                   # indices of the selected items
```

### With fairness constraints

Require a minimum and/or maximum number of selected items from given subsets — useful for fair
representation across groups. Groups may overlap, and infeasible constraints degrade gracefully
to the least-infeasible selection rather than failing.

```python
from max_div import Constraint

# require between 8 and 12 of the selected items from each half of the data
constraints = [
    Constraint(int_set=set(range(0, 100)),   min_count=8, max_count=12),
    Constraint(int_set=set(range(100, 200)), min_count=8, max_count=12),
]
problem = MaxDivProblem.new(vectors, k=20, constraints=constraints)
```

## Documentation

Full documentation lives at **[max-div.readthedocs.io](https://max-div.readthedocs.io)**,
including:

- [Getting started](https://max-div.readthedocs.io/en/stable/getting_started/) — installation,
  distance and diversity metrics, solver presets
- [Comparison with other tools](https://max-div.readthedocs.io/en/stable/comparison/) — how
  max-div relates to exact solvers, greedy pickers, and samplers
- [Benchmarks](https://max-div.readthedocs.io/en/stable/benchmarks/comparison/overview/) — the
  measured comparison against third-party tools

## License

Licensed under the [Apache License 2.0](https://github.com/bertpl/max-div/blob/main/LICENSE).
