Skip to main content

Variable aggregation (reduced-space presolve) plugin for discopt

Project description

discopt-aggregation

CI Documentation arXiv EPL-2.0

Variable aggregation (reduced-space presolve) for nonlinear optimization — a standalone plugin for discopt that installs into the discopt.aggregation namespace.

📖 Documentation

It implements Naik, Biegler, Bent & Parker, Variable aggregation for nonlinear optimization problems (arXiv:2502.13869): substitute variables defined by equality constraints into the rest of a model, eliminating both a variable and a constraint to yield a smaller reduced-space formulation, then recover the eliminated variables from the reduced solution.

import discopt.modeling as dm
from discopt.aggregation import aggregate, solve

m = dm.Model("example")
x = m.continuous("x", lb=-5, ub=5)
y = m.continuous("y", lb=-5, ub=5)
m.subject_to(y - (x + 1) == 0.0)          # y is defined by x
m.minimize(x**2 + y**2)

res = solve(m, method="d2")                # aggregate → solve → recover
print(res.status, res.objective)          # optimal 0.5
print(res.x)                              # {'x': -0.5, 'y': 0.5}  (y recovered)

Installation

pip install discopt-aggregation          # from PyPI

Or from a checkout for development:

uv pip install -e ".[dev]"               # or: pip install -e ".[dev]"

Requires discopt >= 0.6. The plugin is a discopt.aggregation namespace package: it merges into the installed discopt package at import time. This needs discopt/__init__.py to extend its search path, i.e. to contain:

__path__ = __import__("pkgutil").extend_path(__path__, __name__)

discopt 0.6+ includes this line. (If you use an older discopt, add it once.)

Claude skill

This package ships a Claude Code skill that documents how to use aggregation (method choice, the structure-preserving vs Hessian-cost tradeoff, every option, recovery, diagnostics, the study harnesses). Claude Code does not auto-discover skills from installed Python packages, so after pip install run the bundled installer once to copy it into a .claude/skills/ directory Claude scans:

discopt-aggregation-skill install            # -> ./.claude/skills/  (this project)
discopt-aggregation-skill install --user     # -> ~/.claude/skills/  (every project)
discopt-aggregation-skill path               # where the packaged skill lives

Working inside this repo, the skill is already at .claude/skills/ (no install needed). The repo is also a Claude Code plugin (.claude-plugin/plugin.json

  • skills/), so it can be loaded with claude --plugin-dir <repo> or published to a marketplace. The single source of truth is src/discopt/aggregation/skill/; the two .claude/skills / skills entries are symlinks to it.

Methods

method= selects the strategy, most conservative to most aggressive:

key name eliminates paper
ld1 fixed-variable (degree-1) y = a Alg 3
ecd2 equal-coefficient degree-2 y = x + a Alg 6
ld2 linear degree-2 y = a*x + b Alg 5
d2 degree-2 (default) y = f(x) (≤ 2 variables) Alg 4
gr greedy y = f(w, x, …) (y linear) Alg 1
lm linear-matching y = f(w, x, …) (y linear) Alg 2

ld1/ecd2/ld2/d2 are structure-preserving; gr/lm are approximate-maximum. The paper recommends d2; it is the default.

Integer aggregation (opt-in, beyond the paper)

By default only scalar continuous variables are eliminated. Pass aggregate(..., integer_aggregation=True) (or solve(...)) to also eliminate a scalar integer/binary variable — but only when its integrality is implied, the standard MIP-presolve condition (Achterberg et al. 2020): the defining equality is fully affine, the pivot coefficient is ±1, every other variable in it is integer/binary, and every other coefficient and the constant are integral (e.g. an all-integer stock balance s[t] = s[t-1] + q[t] - d[t]). Recovery returns exactly integral values; dual recovery reports available=False over eliminated integers. The flag is default-off and never eliminates a variable it cannot prove integral (fractional data, non-unit pivot, or a continuous participant all abstain), so the default behaviour is unchanged.

Features

  • Six strategies, each producing a strictly lower-triangular aggregation set (Lemma 1) with explicit, solve-free post-solve recovery.
  • Numerical safeguards: a relative pivot tolerance (pivot_tol) against ill-conditioned substitutions, and an optional fill-in cap (max_fill).
  • Redundant-bound pruning (prune_bounds, on by default): box→inequality constraints proven redundant by interval propagation are omitted.
  • Array support (scalarize, on by default): fully-indexed array variables are scalarized so aggregation reaches discretized (DAE) models, then arrays are reassembled on recovery.
  • Structural metrics (compare_methods) reproducing the paper's Table 4, including the exact AD Hessian nonzero count.

Examples

python -m discopt.aggregation.examples runs commented, executable walkthroughs of every method, the recursive pipeline, end-to-end solve + recovery, the structural comparison, the safeguards, array scalarization, and a performance/scaling demo.

Tests

uv pip install -e ".[dev]"
python -m pytest tests/ -q          # the full suite

Layout

src/discopt/aggregation/    # the plugin (PEP 420 namespace subpackage)
  core:        matching · incidence · strategies · transform · recovery · api
  walking:     exprwalk (single DAG-walk authority for all analyses)
  structure:   scalarize · metrics · diagnostics (Dulmage–Mendelsohn) · ordering
  numerics:    guards · hessian_cost · duals · derivatives · implicit · tearing · schur
  study:       testproblems · benchmark · sweep · profiling · presolve · examples
tests/                      # test_aggregation_*.py
design/                     # follow-up roadmap · parity plan · references.bib

References

Primary:

Sakshi Naik, Lorenz Biegler, Russell Bent, Robert Parker. Variable aggregation for nonlinear optimization problems. arXiv:2502.13869 (2025). https://arxiv.org/abs/2502.13869

The full set of related work — reduced-space / implicit elimination (Parker et al. 2022), block-triangular KKT (Parker, Garcia & Bent 2026), exact tearing / minimum feedback set (Baharev et al. 2021), Dulmage–Mendelsohn debugging (Parker et al. 2023), and the MIP-presolve line (Achterberg et al. 2020) — is collected as verified BibTeX in design/references.bib, and cited from the design docs under design/.

Contributing

See CONTRIBUTING.md for dev setup, the lint/type/test gate, and the project conventions (keep discopt/pounce/feral untouched, new behavior opt-in/default-off, a worked example per feature, hash-seed-robust tests).

License

Eclipse Public License 2.0 (EPL-2.0), matching discopt.

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

discopt_aggregation-0.4.1.tar.gz (198.5 kB view details)

Uploaded Source

Built Distribution

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

discopt_aggregation-0.4.1-py3-none-any.whl (147.6 kB view details)

Uploaded Python 3

File details

Details for the file discopt_aggregation-0.4.1.tar.gz.

File metadata

  • Download URL: discopt_aggregation-0.4.1.tar.gz
  • Upload date:
  • Size: 198.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for discopt_aggregation-0.4.1.tar.gz
Algorithm Hash digest
SHA256 c10ffe4c273692180f70e0466fb25345d9d2c808020ee63630e06166997f5575
MD5 71d335166300e4e35b2f5d63b79274ef
BLAKE2b-256 e4fd61ba41b708e69aaf0f53f5f19c6bf92ee569744b41eac58fd9d2ffc14bd9

See more details on using hashes here.

Provenance

The following attestation bundles were made for discopt_aggregation-0.4.1.tar.gz:

Publisher: publish.yml on jkitchin/discopt-aggregation

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

File details

Details for the file discopt_aggregation-0.4.1-py3-none-any.whl.

File metadata

File hashes

Hashes for discopt_aggregation-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ae98f9fbd3c6137a7be5a3113beb4a66d5aba14f16d7341468ab6f9fb6bdf075
MD5 bd7223b18758a8ac3e870312ca8a6bf8
BLAKE2b-256 de7fda6de7160fd6c727675840bbd685bd185e5537f3d73c03d56daf3416bc44

See more details on using hashes here.

Provenance

The following attestation bundles were made for discopt_aggregation-0.4.1-py3-none-any.whl:

Publisher: publish.yml on jkitchin/discopt-aggregation

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