Skip to main content

Gradient-free multi-objective alignment via Sperner's Lemma and implicit Freudenthal triangulation.

Project description

Sperner

Find the optimal balance between competing objectives — without gradients, without grid search, with a mathematical guarantee.

Tests Python 3.10+ License: MIT


What does Sperner do?

You have an LLM (or any system) with N competing objectives — Safety vs. Helpfulness vs. Creativity, or Precision vs. Recall vs. Latency. You need to find the weight mix where everything is "good enough" simultaneously.

Sperner solves this in O(N) evaluations using a topological fixed-point algorithm (Sperner's Lemma), instead of the O(X^N) brute-force grid search.

# Find the optimal balance between 3 objectives in ~50 evaluations
from sperner import solve_equilibrium

weights = solve_equilibrium(
    n_objs=3,
    oracle=lambda w: my_benchmark(w),  # returns index of weakest objective
)
# weights ≈ [0.35, 0.40, 0.25] — the Nash equilibrium

When to use Sperner

Use case Example
LLM alignment Balance safety, helpfulness, and creativity
Model merging Find optimal LoRA adapter mix weights
MoE routing Allocate experts without softmax collapse
Benchmark tuning Hit multiple non-differentiable metrics at once
Any multi-objective problem Where you can answer "which objective is weakest?"

The only requirement: you need an oracle that, given a weight vector, tells you which objective is currently the most underserved. That's it — no gradients, no loss surfaces, no hyperparameter sweeps.


How it works (30-second version)

  1. Sperner places your N objectives on an N-simplex (triangle for 3, tetrahedron for 4, etc.)
  2. It subdivides the simplex into a fine grid and labels each point by asking your oracle: "at these weights, which objective is weakest?"
  3. It performs a Sperner walk — a combinatorial path through the grid that is mathematically guaranteed to find a cell where all labels meet (a "panchromatic simplex")
  4. The centroid of that cell is your equilibrium — the weight mix where no single objective dominates

This works because of Sperner's Lemma (1928): any valid labeling of a triangulated simplex must contain at least one fully-labeled cell. Sperner exploits this to find it in linear time.


Installation

pip install .

# With LoRA/PEFT support
pip install ".[peft]"

# With Streamlit human-in-the-loop UI
pip install ".[ui]"

# Everything
pip install ".[all]"

Quick start

Automated (programmatic oracle)

import numpy as np
from sperner import NDimEquilibSolver
import torch

solver = NDimEquilibSolver(n_objs=4, subdivision=50)

def judge(weights_batch: torch.Tensor) -> torch.Tensor:
    """Return index of the weakest objective for each weight vector."""
    labels = []
    for w in weights_batch:
        scores = run_my_benchmarks(w.numpy())  # your eval function
        labels.append(int(np.argmin(scores)))
    return torch.tensor(labels)

optimal = solver.solve(oracle_fn=judge)
print(f"Optimal weights: {optimal[0]}")

Human-in-the-loop (Streamlit UI)

For qualitative "vibe check" alignment — the solver proposes weights, your local LLM generates a response, and you click which objective needs more work:

streamlit run app.py

The UI supports 2–10 configurable objectives and works with any OpenAI-compatible API (LM Studio, Ollama, vLLM).

LoRA adapter merging

from sperner import SpernerTrainer

trainer = SpernerTrainer(
    base_model=my_peft_model,
    adapters=["safety-lora", "code-lora", "chat-lora"],
    objectives=[safety_score, code_score, chat_score],
    mock=False,
)
optimal_mix = trainer.train(grid_size=50)

MoE expert routing

from sperner import TopologicalMoERouter

router = TopologicalMoERouter(num_experts=8, latent_dim=4096)
weights = router.forward_route(hidden_states, precision=20)
# weights = [0.18, 0.12, 0.15, ...] — no routing collapse

Comparison

Grid Search Bayesian Opt Sperner
Oracle calls O(X^N) exponential O(N²) typical O(N) linear
Needs gradients No No No
Scales to 10+ objectives No Poorly Yes
Convergence guarantee Exhaustive only Probabilistic Mathematical
Works with discrete metrics Yes Awkward Native

Project structure

sperner/
  ndim_solver.py       # Core N-dimensional Sperner walk (PyTorch)
  solver.py            # Legacy 2D solver
  adaptive_solver.py   # Iterative zoom refinement
  surrogate_solver.py  # KNN active-learning wrapper (fewer oracle calls)
  sperner_trainer.py   # PEFT/LoRA adapter integration
  moe_router.py        # Topological MoE routing
  agentic_judge.py     # LLM-as-a-Judge orchestrator
  human_ui.py          # Streamlit UI for manual alignment
  analytics.py         # Frustration score & path analysis
  plotting.py          # Simplex heatmap visualization

Docs

Citation

@software{mesbah2026sperner,
  author = {Mesbah, Oussama},
  title = {Sperner: Gradient-Free Multi-Objective Alignment via Sperner's Lemma},
  year = {2026},
  url = {https://github.com/OussamaMesbah/sperner}
}

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sperner-0.1.0.tar.gz (96.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sperner-0.1.0-py3-none-any.whl (34.6 kB view details)

Uploaded Python 3

File details

Details for the file sperner-0.1.0.tar.gz.

File metadata

  • Download URL: sperner-0.1.0.tar.gz
  • Upload date:
  • Size: 96.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sperner-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e0d1e0fc4769b6727fa2878280f907abf93488533bc2e8490398a1743025348c
MD5 d3dabfb92ce3ef35b900d0b3841c66c1
BLAKE2b-256 7279d33ec9d5e6457d9905bc555ae7b95c083bda7b74e9d218b6aad3cfe08af6

See more details on using hashes here.

Provenance

The following attestation bundles were made for sperner-0.1.0.tar.gz:

Publisher: publish.yml on OussamaMesbah/sperner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sperner-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: sperner-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 34.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for sperner-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 74eff2018e72b09aa21cd011c7feca4851a55940f202411369dfeb9d714ab5cf
MD5 227aee543f3319beb7c2fad5b89c1e21
BLAKE2b-256 b6f4e51450b1a58610fe91a63f5ed6a0fe87acd10a910e9189ec28f9cb993d81

See more details on using hashes here.

Provenance

The following attestation bundles were made for sperner-0.1.0-py3-none-any.whl:

Publisher: publish.yml on OussamaMesbah/sperner

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page