Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Run a single test: `uv run pytest tests/test_coverage.py::TestClass::test_name -
- `core/sisireg3d.py`, `core/sisireg_mlp.py` — Python ports of the remaining solver parts of the R package `sisireg` 1.2.1 (GPL>=2): spatial minimal-surface SSR regression (`ssr3d` family) and the two-layer perceptron trained with the partial sum criterion (`ssrMLP` family). Regression building blocks (not unfolding methods); fixture-tested against the original R output (`tests/data/sisireg3d/`, `tests/data/sisireg_mlp/`)
- `core/unfolding_methods.py` — all `solve_*` functions, ~222 stmts
- `core/unfold_qpsolvers.py`, `unfold_cvxpy.py`, `unfold_landweber.py`, `unfold_mlem.py`, `unfold_mlem_odl.py`, `unfold_doroshenko.py`, `unfold_kaczmarz.py`, `unfold_lmfit.py`, `unfold_smt.py`, `unfold_combined.py`, `unfold_ferdor.py`, `unfold_rebunki.py`, `unfold_nsduaz.py` — one file per unfolding algorithm (unfold_smt.py is a port of the Haskell/SBV `linearEqSolver`, backed by optional z3-solver)
- `core/unfold_commercial.py` — license-required commercial QP solvers (`solve_gurobi`/`unfold_gurobi`, mosek, cplex, copt, xpress): five pre-bound wrappers over the general `solve_commercial`/`unfold_commercial`, driven through cvxpy interfaces **without open-source fallback** (missing engine/license → warn + zero spectrum). Shared QP backend in `core/_commercial_qp.py` (`commercial_solver_info`, `is_commercial_solver_available`); aliases match `Detector` methods and `pip install bssunfold[commercial]` extras. Results follow the canonical `solve_qpsolvers` convention (identity OR derivative Tikhonov penalty, never both). Availability is also reported by `platform_check.check_commercial_solvers_availability()`
- `core/unfold_gee.py` — GEE unfolding (R `gee` 4.13-30 analogue): working-correlation IRLS with Liang-Zeger robust/naive sandwich covariance estimates for the spectrum
- `core/unfold_uno.py` — Uno-style Lagrange-Newton constrained unfolding (R `Uno` analogue, Vanaret & Leyffer 2024): `filter_sqp` preset (exact Hessian QP sub-solve via scipy nnls + Fletcher-Leyffer filter) and `ipopt_like` (primal-dual interior point, exact/BFGS Hessian)
- `core/unfold_interpret.py` — public `interpret_qp`/`unfold_interpret` entry points for pyoptexplain-based interpretation of the unfolding QP (solve + robustness, shadow prices, detector sensitivity, regularization sweep, scenarios). Backed by `core/_interpret_pyopt.py` (QP build/solve + perturbation analyses, leaf) and `core/_interpret_report.py` (result dataclass + markdown report + metrics, leaf). Optional dep: `bssunfold[interpret]`
Expand Down
60 changes: 60 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,66 @@ The format is based on [Keep a Changelog],

and this project adheres to [Semantic Versioning].

## [Unreleased]

### Added

- **License-required commercial QP solver methods** — five new unfolding
methods `unfold_gurobi`, `unfold_mosek`, `unfold_cplex`, `unfold_copt`
and `unfold_xpress` (plus `solve_gurobi`, `solve_mosek`, `solve_cplex`,
`solve_copt`, `solve_xpress`), driving the proprietary engines of
Gurobi, MOSEK, IBM CPLEX, Cardinal Optimizer (COPT) and FICO Xpress
through their cvxpy interfaces. Each method solves the same
Tikhonov-regularized non-negative least-squares QP as the open-source
path (`0.5*||A x - b||^2` plus an identity *or* derivative penalty,
L1/L2 norm options, Monte-Carlo uncertainty, `max_neutron_energy`
support). **License required**: bssunfold never ships or checks a
license; the engine package (`gurobipy`, `mosek`, `cplex`, `coptpy`,
`xpress`) must be installed and licensed on the machine. Unlike
`unfold_cvxpy` there is **no open-source fallback** — a missing engine
or license warns and yields a zero spectrum, so results always come
from the licensed engine that was requested.
- New general entry points `solve_commercial` / `unfold_commercial`
taking a `solver=` alias, and metadata helpers
`commercial_solver_info` / `is_commercial_solver_available`; the five
public wrappers are pre-bound partials of these. New file
`core/unfold_commercial.py` with the shared QP backend
`core/_commercial_qp.py` (cvxpy `quad_form` build + solve, kwargs
retry, non-optimal/license-error handling).
- New `Detector` methods `unfold_gurobi`, `unfold_mosek`,
`unfold_cplex`, `unfold_copt`, `unfold_xpress` (full canonical
signatures); all names registered in `core/__init__.py`.
- New optional extras in `pyproject.toml`: `[gurobi]`, `[mosek]`,
`[cplex]`, `[copt]`, `[xpress]` and the aggregate `[commercial]` —
deliberately **not** included in `[all]` because they are
license-required proprietary packages (`pip install
"bssunfold[commercial]"` after obtaining licenses).
- `platform_check`: new `check_commercial_solvers_availability()`
(probes cvxpy `installed_solvers()` for the five engines, cached in
`COMMERCIAL_SOLVERS_AVAILABLE`) and per-solver entries in
`get_available_solvers()`.
- New test file `tests/test_commercial.py` (63 tests): solver metadata
and alias validation, graceful zero-spectrum + warning behaviour for
unavailable engines (each missing engine exercised via
`block_import`), ill-formed input and norm guards (`norm=1` requires
`nonneg`), end-to-end numerics with the licensed CPLEX engine where
installed (L2/L1/smoothness/`ub`/warm start, agreement with a
tight-tolerance qpsolvers reference, objective equality), solver
failure paths (mocked `Problem.solve` errors and non-optimal
status), Monte-Carlo/`save_result`/`regularization_method` integration
and `max_neutron_energy` masking. The commercial methods are wired
into `tests/test_all_unfold_methods_api.py` with auto-skip when the
engine package is not installed (CPLEX runs for real in the dev
environment).

### Documentation

- README, `docs/index.rst`, `docs/overview.rst`, `docs/examples.rst`,
`docs/math_formulation.rst` and `docs/detector.rst` updated with the
five license-required methods (method tables, mermaid family maps,
variational-formulation section, autodoc entries, installation extras
with explicit **license required** notes); method count 94 → 99.

## [0.28.0] - 2026-09-21

### Added
Expand Down
Loading
Loading