Skip to main content

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_pounce is required. Without it, SolverFactory('pounce') raises a clear UnknownSolver / "plugin not registered" error — it does not silently run some other pounce. With it imported, the plugin runs the pounce binary bundled in the pounce-solver wheel, independent of PATH. Only a source/dev install without that wheel falls back to a pounce on PATH, in which case the plugin warns.

To see exactly which binary will run (and whether a stale or unrelated pounce earlier on PATH would 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 same X.Y.Z while 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 routepip install pyomo-pounce[pyomo-v2] asks for both:

  • Pyomo ≥ 6.10.1, which is where the SolutionLoader / get_vars API this builds on landed. (pyomo.contrib.solver.common exists from 6.9.2, but 6.9.2–6.10.0 ship the older SolutionLoaderBase / get_primals.)
  • pounce-solver > 0.9.0. The v2 route reads the .sol through Pyomo's asl_sol_reader, which is strict where the legacy reader is lenient, so it needs the per-model Options echo added after 0.9.0.

Neither applies to SolverFactory('pounce'). On an older Pyomo, import pyomo_pounce still works and the legacy plugin behaves exactly as before; pyomo_pounce.HAVE_V2_INTERFACE reports 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:

  1. Build POUNCE from source and put it on PATH — the plugin resolves pounce via shutil.which, so any binary on PATH works:

    # in the pounce repo
    cargo build --release --bin pounce
    export PATH="$PWD/target/release:$PATH"
    pip install --no-deps pyomo-pounce pyomo
    
  2. Install pounce-solver from source via maturin:

    make -C pounce dev     # maturin develop --release + the bundled CLI
    pip install pyomo-pounce
    

    make dev rather than a bare maturin 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's target/release/pounce (warning that it did) or, failing that, to whatever pounce is on PATH — 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

pyomo_pounce-0.11.0.tar.gz (211.6 kB view details)

Uploaded Source

Built Distribution

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

pyomo_pounce-0.11.0-py3-none-any.whl (95.9 kB view details)

Uploaded Python 3

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

Hashes for pyomo_pounce-0.11.0.tar.gz
Algorithm Hash digest
SHA256 eae3b326ca8d447fe5970c61b00c7b49113900a40acc6a21c503e7b0c1d9dddb
MD5 ef93ef9a8dc8765dfd2c9168025f777b
BLAKE2b-256 53245484bf20d1ecf09391ea217d02e1e6759f8ed39d9984a56c469403950d4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyomo_pounce-0.11.0.tar.gz:

Publisher: release-pyomo-pounce.yml on jkitchin/pounce

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

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

Hashes for pyomo_pounce-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7603c00d902a2a68087aec6ca27f0f3acc08d26e41d9e3967742a8586ab99fb1
MD5 31ed8117c69b456ea06917702244a348
BLAKE2b-256 8b00caf0089c46ce92cab10be63bc9ffd490647e6450f2b004d416b511cda414

See more details on using hashes here.

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

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

Release history Release notifications | RSS feed

This release

0.11.0 This release

2 files

0.10.0

2 files

0.9.0

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page