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:

    cd pounce/python && maturin develop --release
    # then `cargo install --path ../crates/pounce-cli` to get the CLI
    # since maturin develop does not bundle the binary.
    pip install pyomo-pounce
    

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 and falls back to PATH only when that is absent. Neither setup above bundles anything, so a plain source checkout takes the fallback path 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.10.0.tar.gz (140.9 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.10.0-py3-none-any.whl (81.1 kB view details)

Uploaded Python 3

File details

Details for the file pyomo_pounce-0.10.0.tar.gz.

File metadata

  • Download URL: pyomo_pounce-0.10.0.tar.gz
  • Upload date:
  • Size: 140.9 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.10.0.tar.gz
Algorithm Hash digest
SHA256 9e0c57e4dca616f68be044892145082dfb4df25dc5264041063cf91af3dcf17f
MD5 ac949e1e8b3c8ee5c5f96bca0ab61842
BLAKE2b-256 f8ede4d2fb0854cf826a286667f90e206c0c50749cc5de265817266c429aec5e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyomo_pounce-0.10.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.10.0-py3-none-any.whl.

File metadata

  • Download URL: pyomo_pounce-0.10.0-py3-none-any.whl
  • Upload date:
  • Size: 81.1 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.10.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3747bea1746d39f8583229f26c5d2cd68c8524606cb4e6109251cd3e659e5584
MD5 c418adced6d6e92d5475528a750f6765
BLAKE2b-256 e902952ed2e95f729cce3ed9887d540765f12e89cdc07c34219403142b5b3d73

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyomo_pounce-0.10.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

0.11.0

2 files

This release

0.10.0 This release

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