Skip to content

Commit 31a81ad

Browse files
isPANNclaude
andauthored
Add ILP solver backends (HiGHS, CPLEX, lp-solvers) and fix good_lp compatibility (#792)
* refactor: upgrade good_lp to 1.15.0 and add lp-solvers backend (#787) - Upgrade good_lp from 1.14.2 to 1.15.0 - Add ilp-lp-solvers feature for Gurobi/CPLEX/CBC/GLPK support (via lp-solvers crate, which shells out to solver CLIs) - Remove unused backend features (coin-cbc, clarabel, scip, lpsolve, microlp) - Update CLI help text Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add prism graph HC→QAP→ILP roundtrip test (#780) Verifies the full reduction chain HamiltonianCircuit → QuadraticAssignment → ILP on the prism graph (6 vertices, 9 edges) — the instance that triggered #780. Confirms the extracted solution is a valid HC. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: replace lp-solvers with cplex backend CPLEX is supported natively by good_lp via cplex-rs (direct C API), no need for the lp-solvers shell-out approach. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: remove prism graph roundtrip test Temporary test to verify #780 fix — no longer needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add lpsolve backend Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add all good_lp solver backends Add coin-cbc, clarabel, scip, microlp, and lp-solvers (Gurobi/GLPK via CLI). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: keep only useful ILP backends (HiGHS, CPLEX, lp-solvers) Remove coin-cbc, clarabel, scip, microlp, lpsolve — either inferior to HiGHS or niche. lp-solvers covers Gurobi/GLPK via CLI shell-out. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * test: add prism graph HC→QAP→ILP roundtrip test Restores the prism graph (6 vertices, 9 edges) end-to-end test that exercises the HC → QAP → ILP → solve → extract pipeline. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: downgrade good_lp to 1.14.2 to fix lp-solvers build on Rust 1.90 good_lp 1.15.0 uses `gen` as a variable name, which is a reserved keyword in newer Rust compilers, breaking the lp-solvers feature. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e1b41bd commit 31a81ad

4 files changed

Lines changed: 43 additions & 14 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ example-db = []
1717
ilp = ["ilp-highs"] # backward compat shorthand
1818
ilp-solver = [] # marker: enables ILP solver code
1919
ilp-highs = ["ilp-solver", "dep:good_lp", "good_lp/highs"]
20-
ilp-coin-cbc = ["ilp-solver", "dep:good_lp", "good_lp/coin_cbc"]
21-
ilp-clarabel = ["ilp-solver", "dep:good_lp", "good_lp/clarabel"]
22-
ilp-scip = ["ilp-solver", "dep:good_lp", "good_lp/scip"]
23-
ilp-lpsolve = ["ilp-solver", "dep:good_lp", "good_lp/lpsolve"]
24-
ilp-microlp = ["ilp-solver", "dep:good_lp", "good_lp/microlp"]
20+
ilp-cplex = ["ilp-solver", "dep:good_lp", "good_lp/cplex-rs"]
21+
ilp-lp-solvers = ["ilp-solver", "dep:good_lp", "good_lp/lp-solvers"]
2522

2623
[dependencies]
2724
petgraph = { version = "0.8", features = ["serde-1"] }

problemreductions-cli/Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@ default = ["highs"]
1919
all = ["highs", "mcp"]
2020
highs = ["problemreductions/ilp-highs"]
2121
mcp = ["dep:rmcp", "dep:tokio", "dep:schemars", "dep:tracing", "dep:tracing-subscriber"]
22-
coin-cbc = ["problemreductions/ilp-coin-cbc"]
23-
clarabel = ["problemreductions/ilp-clarabel"]
24-
scip = ["problemreductions/ilp-scip"]
25-
lpsolve = ["problemreductions/ilp-lpsolve"]
26-
microlp = ["problemreductions/ilp-microlp"]
22+
cplex = ["problemreductions/ilp-cplex"]
23+
lp-solvers = ["problemreductions/ilp-lp-solvers"]
2724

2825
[dependencies]
2926
problemreductions = { version = "0.4.0", path = "..", default-features = false, features = ["example-db"] }

problemreductions-cli/src/cli.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -767,10 +767,9 @@ Customized solver: exact witness recovery for select problems via structure-expl
767767
backends. Currently supports MinimumCardinalityKey, AdditionalKey, PrimeAttributeName,
768768
BoyceCoddNormalFormViolation, PartialFeedbackEdgeSet, and RootedTreeArrangement.
769769
770-
ILP backend (default: HiGHS). To use a different backend:
771-
cargo install problemreductions-cli --features coin-cbc
772-
cargo install problemreductions-cli --features scip
773-
cargo install problemreductions-cli --no-default-features --features clarabel")]
770+
ILP backend (default: HiGHS). To use CPLEX instead:
771+
cargo install problemreductions-cli --features cplex
772+
(Requires CPLEX to be installed on your system.)")]
774773
pub struct SolveArgs {
775774
/// Problem JSON file (from `pred create`) or reduction bundle (from `pred reduce`). Use - for stdin.
776775
pub input: PathBuf,

src/unit_tests/rules/hamiltoniancircuit_quadraticassignment.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,39 @@ fn test_hamiltoniancircuit_to_quadraticassignment_extract_solution() {
110110
"extracted solution should be a valid HC"
111111
);
112112
}
113+
114+
#[cfg(feature = "ilp-solver")]
115+
#[test]
116+
fn test_prism_graph_hc_via_qap_ilp_roundtrip() {
117+
use crate::models::algebraic::ILP;
118+
use crate::solvers::ILPSolver;
119+
120+
// Prism graph: 6 vertices, 9 edges — the instance from #780.
121+
let edges = vec![
122+
(0, 1),
123+
(1, 2),
124+
(2, 0),
125+
(3, 4),
126+
(4, 5),
127+
(5, 3),
128+
(0, 3),
129+
(1, 4),
130+
(2, 5),
131+
];
132+
let hc = HamiltonianCircuit::new(SimpleGraph::new(6, edges));
133+
134+
// HC → QAP → ILP → solve → extract back
135+
let r1 = ReduceTo::<QuadraticAssignment>::reduce_to(&hc);
136+
let r2 = ReduceTo::<ILP<bool>>::reduce_to(r1.target_problem());
137+
let ilp_sol = ILPSolver::new()
138+
.solve(r2.target_problem())
139+
.expect("ILP should be feasible");
140+
let qap_sol = r2.extract_solution(&ilp_sol);
141+
let hc_sol = r1.extract_solution(&qap_sol);
142+
143+
assert!(
144+
hc.evaluate(&hc_sol).0,
145+
"prism graph HC via QAP→ILP should produce a valid Hamiltonian circuit, got {:?}",
146+
hc_sol
147+
);
148+
}

0 commit comments

Comments
 (0)