pyomo-pounce
Pyomo solver plugin for POUNCE, a pure-Rust interior-point NLP solver (a Rust port of IPOPT).
POUNCE speaks the AMPL NL/SOL protocol, so Pyomo drives it through the AMPL Solver Library interface — exactly how Pyomo integrates with IPOPT.
Installation
pip install pyomo-pounce
That single command pulls in the pounce-solver dependency, which
ships a per-platform wheel bundling the pounce executable. After
install, pounce is on your PATH and Pyomo finds it automatically.
Usage
import pyomo_pounce # registers the solver — REQUIRED before SolverFactory('pounce')
from pyomo.environ import *
model = ConcreteModel()
model.x = Var(initialize=0.5)
model.obj = Objective(expr=(model.x - 2)**2)
solver = SolverFactory('pounce')
result = solver.solve(model, tee=True)
print(f"x* = {value(model.x)}") # 2.0
import pyomo_pounceis required. Without it,SolverFactory('pounce')raises a clearUnknownSolver/ "plugin not registered" error — it does not silently run some otherpounce. With it imported, the plugin runs thepouncebinary bundled in thepounce-solverwheel, independent ofPATH. Only a source/dev install without that wheel falls back to apounceonPATH, in which case the plugin warns.To see exactly which binary will run (and whether a stale or unrelated
pounceearlier onPATHwould shadow it), call:import pyomo_pounce pyomo_pounce.check_binary()The check compares the git commit embedded in
pounce --about, not the version string — two builds can share the sameX.Y.Zwhile differing in behavior (as a binary from before/after a fix does).
Pyomo's modern (pyomo.contrib.solver) interface
The same solver is registered against Pyomo's newer solver interface —
the one ipopt_v2 uses — carrying every extra on this page:
import pyomo_pounce
from pyomo.contrib.solver.common.factory import SolverFactory as SolverFactoryV2
solver = SolverFactoryV2('pounce') # returns a v2 Results object
results = solver.solve(model)
print(results.solution_status, results.incumbent_objective)
SolverFactory('pounce_v2') gives the same engine behind the legacy API,
mirroring Pyomo's own ipopt / ipopt_v2 split. SolverFactory('pounce')
is unchanged and remains fully supported.
Both routes return the same numbers — a test solves one model through
each and compares primals, objective, duals and reduced costs. They
differ in API (v2 returns Results and hands the solution back through a
loader, so load_solutions=False gives you values without touching the
model; options are solver_options={...} rather than options={...})
and in per-solve overhead outside the solve, which on IDAES-shaped
collocation models is roughly 0.25 s/solve lower on v2. See
the Pyomo docs page for
the measurements.
Pointing ipopt_v2 at the pounce binary by hand also works, but
silently drops all of the above — the integer-variable guard, the
scaling_factor handling, the sensitivity path and the bundled-binary
resolution. Prefer one of the two registrations above.
Requirements for the v2 route —
pip install pyomo-pounce[pyomo-v2]asks for both:
- Pyomo ≥ 6.10.1, which is where the
SolutionLoader/get_varsAPI this builds on landed. (pyomo.contrib.solver.commonexists from 6.9.2, but 6.9.2–6.10.0 ship the olderSolutionLoaderBase/get_primals.)- pounce-solver > 0.9.0. The v2 route reads the
.solthrough Pyomo'sasl_sol_reader, which is strict where the legacy reader is lenient, so it needs the per-modelOptionsecho added after 0.9.0.Neither applies to
SolverFactory('pounce'). On an older Pyomo,import pyomo_pouncestill works and the legacy plugin behaves exactly as before;pyomo_pounce.HAVE_V2_INTERFACEreports whether the v2 names are available.
Solver Options
Pass options the same way as IPOPT:
solver = SolverFactory('pounce')
solver.options['max_iter'] = 1000
solver.options['tol'] = 1e-10
solver.options['print_level'] = 5
Options are forwarded to POUNCE's OptionsList (ipopt.opt-compatible
keys).
User scaling
The standard scaling_factor Suffix works as it does with IPOPT:
model.scaling_factor = Suffix(direction=Suffix.EXPORT)
model.scaling_factor[model.obj] = 1e-3
model.scaling_factor[model.mass_balance] = 1e2
solver.solve(model, options={'nlp_scaling_method': 'user-scaling'})
Both halves are needed — the Suffix alone is inert (it also drives
Pyomo's own core.scale_model), and the option alone has nothing to
apply, which pyomo-pounce warns about. Untagged components are
unscaled; inactive constraints and fixed variables are skipped.
POUNCE models objective and constraint scaling only, so a
scaling_factor on a Var raises rather than being silently
dropped (#483) —
rescale those variables in the model instead.
Local development / unsupported platforms
If pounce-solver does not ship a wheel for your platform, the pip
install fails on the dependency. Two workarounds:
-
Build POUNCE from source and put it on
PATH— the plugin resolvespounceviashutil.which, so any binary onPATHworks:# in the pounce repo cargo build --release --bin pounce export PATH="$PWD/target/release:$PATH" pip install --no-deps pyomo-pounce pyomo
-
Install
pounce-solverfrom source via maturin:make -C pounce dev # maturin develop --release + the bundled CLI pip install pyomo-pounce
make devrather than a barematurin develop --release: maturin builds the extension module and not the CLI, and this plugin shells out to the CLI. Without it the plugin falls through to the checkout'starget/release/pounce(warning that it did) or, failing that, to whateverpounceis onPATH— see gh #816.
Running the tests locally
Which binary the tests exercise depends on whether a bundled one is
present: the plugin prefers pounce/bin/pounce inside the installed
pounce-solver package, then the surrounding checkout's own
target/release/pounce or target/debug/pounce, and reaches PATH only
when there is neither (gh #816). Setup 1 above bundles nothing, so a plain
source checkout takes one of the fallback rungs while CI takes the bundled
one. Tests that describe the bundled arrangement then skip, and the suite you
run locally is not the suite CI runs.
To match CI, stage the freshly built CLI into the package before building
the wheel — this is what .github/workflows/ci.yml does:
cargo build --release --bin pounce
mkdir -p python/pounce/bin
cp target/release/pounce python/pounce/bin/pounce # the step that bundles it
(cd python && maturin build --release --out dist)
pip install python/dist/*.whl # pounce module + bundled CLI
pip install --no-deps -e pyomo-pounce
pytest pyomo-pounce/tests -q
networkx and scipy are needed for test_block_init.py and
test_repair.py; without them those two files skip.
If a test involving duals, multipliers, or bound reduced costs fails, check the binary before the code:
import pyomo_pounce; pyomo_pounce.check_binary()
It reports which executable will actually run, its build commit, and
whether anything on PATH shadows it. Two builds can share a version
string while differing in commit, so a stale binary reports a plausible
X.Y.Z while returning pre-fix results — that is the failure mode gh #315
added check_binary() for, and the one gh #366 turned out to be about.
License
EPL-2.0, same as POUNCE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyomo_pounce-0.11.0.tar.gz.
File metadata
- Download URL: pyomo_pounce-0.11.0.tar.gz
- Upload date:
- Size: 211.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eae3b326ca8d447fe5970c61b00c7b49113900a40acc6a21c503e7b0c1d9dddb
|
|
| MD5 |
ef93ef9a8dc8765dfd2c9168025f777b
|
|
| BLAKE2b-256 |
53245484bf20d1ecf09391ea217d02e1e6759f8ed39d9984a56c469403950d4c
|
Provenance
The following attestation bundles were made for pyomo_pounce-0.11.0.tar.gz:
Publisher:
release-pyomo-pounce.yml on jkitchin/pounce
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyomo_pounce-0.11.0.tar.gz -
Subject digest:
eae3b326ca8d447fe5970c61b00c7b49113900a40acc6a21c503e7b0c1d9dddb - Sigstore transparency entry: 2703757885
- Sigstore integration time:
-
Permalink:
jkitchin/pounce@4a2ac2b106725016ce719ac17b6f44fb043d5576 -
Branch / Tag:
refs/tags/pyomo-pounce-v0.11.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pyomo-pounce.yml@4a2ac2b106725016ce719ac17b6f44fb043d5576 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyomo_pounce-0.11.0-py3-none-any.whl.
File metadata
- Download URL: pyomo_pounce-0.11.0-py3-none-any.whl
- Upload date:
- Size: 95.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7603c00d902a2a68087aec6ca27f0f3acc08d26e41d9e3967742a8586ab99fb1
|
|
| MD5 |
31ed8117c69b456ea06917702244a348
|
|
| BLAKE2b-256 |
8b00caf0089c46ce92cab10be63bc9ffd490647e6450f2b004d416b511cda414
|
Provenance
The following attestation bundles were made for pyomo_pounce-0.11.0-py3-none-any.whl:
Publisher:
release-pyomo-pounce.yml on jkitchin/pounce
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyomo_pounce-0.11.0-py3-none-any.whl -
Subject digest:
7603c00d902a2a68087aec6ca27f0f3acc08d26e41d9e3967742a8586ab99fb1 - Sigstore transparency entry: 2703758280
- Sigstore integration time:
-
Permalink:
jkitchin/pounce@4a2ac2b106725016ce719ac17b6f44fb043d5576 -
Branch / Tag:
refs/tags/pyomo-pounce-v0.11.0 - Owner: https://github.com/jkitchin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-pyomo-pounce.yml@4a2ac2b106725016ce719ac17b6f44fb043d5576 -
Trigger Event:
push
-
Statement type: