From 97dfd835d741f57bb9ec65eff2629fbd8bfe64bc Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Mon, 16 Mar 2026 22:32:33 +0800 Subject: [PATCH 1/7] Add plan for #500: [Model] SequencingToMinimizeMaximumCumulativeCost --- ...ing-to-minimize-maximum-cumulative-cost.md | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md diff --git a/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md b/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md new file mode 100644 index 000000000..f6d38c549 --- /dev/null +++ b/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md @@ -0,0 +1,238 @@ +# Sequencing to Minimize Maximum Cumulative Cost Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add the `SequencingToMinimizeMaximumCumulativeCost` decision model, its registry/CLI/example-db/test wiring, and the matching paper entry for issue #500. + +**Architecture:** Implement this as a `misc` satisfaction problem with constructor-facing fields `costs: Vec`, `precedences: Vec<(usize, usize)>`, and `bound: i64`. Encode schedules with Lehmer-code dimensions `[n, n-1, ..., 1]`, decode to a permutation during evaluation, reject precedence violations, and accept exactly those schedules whose running cumulative cost never exceeds `bound`. + +**Tech Stack:** Rust library crate, registry inventory metadata, clap-based CLI creation flow, example-db canonical examples, Typst paper docs. + +--- + +## Batch 1: Model, registration, CLI, tests + +### Task 1: Add the core model and its failing tests + +**Files:** +- Create: `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` +- Create: `src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` +- Modify: `src/models/misc/mod.rs` +- Modify: `src/models/mod.rs` +- Modify: `src/lib.rs` + +**Step 1: Write the failing tests** + +Add tests that pin down the intended representation and semantics: +- construction/getters: `costs()`, `precedences()`, `bound()`, `num_tasks()`, `num_precedences()` +- `dims()` uses Lehmer code (`[n, n-1, ..., 1]`) +- `evaluate()` accepts the issue’s feasible schedule and rejects: + - a Lehmer digit outside its domain + - a precedence-violating schedule + - a schedule whose cumulative maximum exceeds `bound` +- brute-force finds a satisfying schedule for the paper/issue example and finds none for a cyclic-precedence or too-tight instance +- serde round-trip + +Use the issue example as the main satisfaction instance: +- `costs = [2, -1, 3, -2, 1, -3]` +- `precedences = [(0, 2), (1, 2), (1, 3), (2, 4), (3, 5), (4, 5)]` +- `bound = 4` +- schedule `t2, t1, t4, t3, t5, t6` (0-indexed `[1, 0, 3, 2, 4, 5]`) should be encoded to its Lehmer form and asserted satisfying + +**Step 2: Run the tests to verify they fail** + +Run: `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` + +Expected: failures because the model file and test module link do not exist yet. + +**Step 3: Write the minimal model implementation** + +Implement `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` with: +- `inventory::submit!` schema metadata +- `#[derive(Debug, Clone, Serialize, Deserialize)]` model struct +- constructor validations: + - `costs.len()` defines `num_tasks` + - every precedence endpoint is in range +- getters: `costs()`, `precedences()`, `bound()`, `num_tasks()`, `num_precedences()` +- `Problem` impl with `Metric = bool` +- Lehmer-code `dims()` +- permutation decoder helper +- cumulative-cost checker over decoded schedule +- `impl SatisfactionProblem` +- `crate::declare_variants! { default sat ... => "factorial(num_tasks)" }` +- test-module link at file end + +Register the model in: +- `src/models/misc/mod.rs` +- `src/models/mod.rs` +- `src/lib.rs` + +**Step 4: Run the tests to verify they pass** + +Run: `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` + +Expected: the new model tests pass. + +**Step 5: Commit** + +```bash +git add src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ + src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ + src/models/misc/mod.rs src/models/mod.rs src/lib.rs +git commit -m "Add SequencingToMinimizeMaximumCumulativeCost model" +``` + +### Task 2: Wire example-db and trait consistency + +**Files:** +- Modify: `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` +- Modify: `src/models/misc/mod.rs` +- Modify: `src/unit_tests/trait_consistency.rs` + +**Step 1: Write the failing tests** + +Add: +- a canonical model example builder in the model file under `#[cfg(feature = "example-db")]` +- a `trait_consistency` entry for the new model +- a paper/example consistency test in the model test file that: + - constructs the exact issue example + - checks the documented satisfying Lehmer code + - checks the brute-force satisfying set is non-empty and includes a satisfying schedule + +**Step 2: Run the focused tests** + +Run: `cargo test trait_consistency sequencing_to_minimize_maximum_cumulative_cost --lib` + +Expected: failures until the example-db hook and consistency wiring are added. + +**Step 3: Implement the wiring** + +Add the canonical example spec in the model file and extend `src/models/misc/mod.rs` so the misc example registry includes it. Update `src/unit_tests/trait_consistency.rs` with `check_problem_trait(...)` for a small instance. + +**Step 4: Re-run the focused tests** + +Run: `cargo test trait_consistency sequencing_to_minimize_maximum_cumulative_cost --lib` + +Expected: passing tests. + +**Step 5: Commit** + +```bash +git add src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ + src/models/misc/mod.rs \ + src/unit_tests/trait_consistency.rs +git commit -m "Wire examples and trait checks for issue #500" +``` + +### Task 3: Add CLI create support + +**Files:** +- Modify: `problemreductions-cli/src/cli.rs` +- Modify: `problemreductions-cli/src/commands/create.rs` + +**Step 1: Write the failing CLI tests** + +Add or extend `pred create` tests covering: +- explicit creation with `--costs`, `--bound`, and optional `--precedence-pairs` +- validation that precedence endpoints are within range +- omission of `--precedence-pairs` for an unconstrained instance + +Prefer constructor-facing CLI fields: +- `--costs` +- `--bound` +- `--precedence-pairs` + +**Step 2: Run the CLI tests to verify they fail** + +Run: `cargo test create:: sequencing_to_minimize_maximum_cumulative_cost` + +Expected: failures because the new flags/help/match arm do not exist yet. + +**Step 3: Implement CLI support** + +Update: +- `CreateArgs` with a `costs` string flag for this problem +- `all_data_flags_empty()` to include the new flag +- the create help table with a `SequencingToMinimizeMaximumCumulativeCost --costs, --bound [--precedence-pairs]` entry +- `problem_examples()` / usage text in `create.rs` +- the main `create()` match to parse `i64` costs, reuse `--precedence-pairs`, validate endpoint ranges against `costs.len()`, and serialize the new model + +**Step 4: Re-run the CLI tests** + +Run: `cargo test create:: sequencing_to_minimize_maximum_cumulative_cost` + +Expected: passing CLI tests. + +**Step 5: Commit** + +```bash +git add problemreductions-cli/src/cli.rs problemreductions-cli/src/commands/create.rs +git commit -m "Add pred create support for issue #500" +``` + +## Batch 2: Paper entry + +### Task 4: Document the model in the paper + +**Files:** +- Modify: `docs/paper/reductions.typ` +- Modify: `docs/paper/references.bib` (only if one of the needed citations is missing) + +**Step 1: Write the paper changes** + +Add: +- display-name entry for `SequencingToMinimizeMaximumCumulativeCost` +- `problem-def("SequencingToMinimizeMaximumCumulativeCost")` +- background and algorithm notes citing: + - Garey & Johnson A5 SS7 + - Abdel-Wahab (1976) for NP-completeness / register-sufficiency connection + - Abdel-Wahab & Kameda (1978) for the series-parallel polynomial case + - Monma & Sidney (1979), correcting the issue’s wrong year +- a worked example using the same 6-task instance as the model tests +- explicit explanation that the example schedule keeps the running cumulative cost at most `K = 4` + +Keep the paper example aligned with the canonical example/tested Lehmer code from Batch 1. + +**Step 2: Build the paper** + +Run: `make paper` + +Expected: Typst compiles successfully and the new `problem-def` renders without missing display-name or example-db references. + +**Step 3: Commit** + +```bash +git add docs/paper/reductions.typ +git commit -m "Document issue #500 in the paper" +``` + +## Final verification and review + +### Task 5: Full verification + +**Files:** +- Modify as needed from verification fixes + +**Step 1: Run repo verification** + +Run: +- `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` +- `cargo test trait_consistency --lib` +- `cargo test create:: --package problemreductions-cli` +- `make test` +- `make clippy` + +Expected: all commands pass. + +**Step 2: Run implementation review** + +Run the repo-local review skill after Batch 1 and again after any verification-driven fixes if needed. Auto-fix structural issues before pushing. + +**Step 3: Clean up the plan file after implementation** + +When the code and docs are complete, remove this plan file before the final implementation push: + +```bash +git rm docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md +git commit -m "chore: remove issue #500 plan file" +``` From ea37ad0aeb25ac6b6fa1a03a4fcc3403455384fb Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Mon, 16 Mar 2026 23:08:36 +0800 Subject: [PATCH 2/7] Implement #500: [Model] SequencingToMinimizeMaximumCumulativeCost --- docs/paper/reductions.typ | 77 ++++++++ docs/paper/references.bib | 22 +++ docs/src/reductions/problem_schemas.json | 21 +++ docs/src/reductions/reduction_graph.json | 27 ++- problemreductions-cli/src/cli.rs | 4 + problemreductions-cli/src/commands/create.rs | 106 ++++++++--- problemreductions-cli/tests/cli_tests.rs | 141 ++++++++++++++ src/example_db/fixtures/examples.json | 1 + src/lib.rs | 3 +- src/models/misc/mod.rs | 4 + ...ing_to_minimize_maximum_cumulative_cost.rs | 178 ++++++++++++++++++ src/models/mod.rs | 3 +- ...ing_to_minimize_maximum_cumulative_cost.rs | 129 +++++++++++++ src/unit_tests/trait_consistency.rs | 4 + 14 files changed, 680 insertions(+), 40 deletions(-) create mode 100644 src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs create mode 100644 src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ index 707822b03..590d8f169 100644 --- a/docs/paper/reductions.typ +++ b/docs/paper/reductions.typ @@ -108,6 +108,7 @@ "PartitionIntoTriangles": [Partition Into Triangles], "FlowShopScheduling": [Flow Shop Scheduling], "MinimumTardinessSequencing": [Minimum Tardiness Sequencing], + "SequencingToMinimizeMaximumCumulativeCost": [Sequencing to Minimize Maximum Cumulative Cost], ) // Definition label: "def:" — each definition block must have a matching label @@ -2091,6 +2092,82 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS ] } +#{ + let x = load-model-example("SequencingToMinimizeMaximumCumulativeCost") + let costs = x.instance.costs + let precs = x.instance.precedences + let bound = x.instance.bound + let ntasks = costs.len() + let sample = x.samples.at(0) + let satisfying-count = x.optimal.len() + let lehmer = sample.config + let schedule = { + let avail = range(ntasks) + let result = () + for c in lehmer { + result.push(avail.at(c)) + avail = avail.enumerate().filter(((i, v)) => i != c).map(((i, v)) => v) + } + result + } + let prefix-sums = { + let running = 0 + let result = () + for task in schedule { + running += costs.at(task) + result.push(running) + } + result + } + [ + #problem-def("SequencingToMinimizeMaximumCumulativeCost")[ + Given a set $T$ of $n$ tasks, a precedence relation $prec.eq$ on $T$, an integer cost function $c: T -> ZZ$ (negative values represent profits), and a bound $K in ZZ$, determine whether there exists a one-machine schedule $sigma: T -> {1, 2, dots, n}$ that respects the precedence constraints and satisfies + $sum_(sigma(t') lt.eq sigma(t)) c(t') lt.eq K$ + for every task $t in T$. + ][ + Sequencing to Minimize Maximum Cumulative Cost is the scheduling problem SS7 in Garey & Johnson @garey1979. It is NP-complete by transformation from Register Sufficiency, even when every task cost is in ${-1, 0, 1}$ @garey1979. The problem models precedence-constrained task systems with resource consumption and release, where a negative cost corresponds to a profit or resource refund accumulated as the schedule proceeds. + + When the precedence constraints form a series-parallel digraph, #cite(, form: "prose") gave a polynomial-time algorithm running in $O(n^2)$ time. #cite(, form: "prose") placed the problem in a broader family of sequencing objectives solvable efficiently on series-parallel precedence structures. The implementation here uses Lehmer-code enumeration of task orders, so the direct exact search induced by the model runs in $O(n!)$ time. + + *Example.* Consider $n = #ntasks$ tasks with costs $(#costs.map(c => str(c)).join(", "))$, precedence constraints #{precs.map(p => [$t_#(p.at(0) + 1) prec.eq t_#(p.at(1) + 1)$]).join(", ")}, and bound $K = #bound$. The sample schedule $(#schedule.map(t => $t_#(t + 1)$).join(", "))$ has cumulative sums $(#prefix-sums.map(v => str(v)).join(", "))$, so every prefix stays at or below $K = #bound$. Our brute-force solver finds exactly #satisfying-count satisfying schedules for this instance. + + #figure( + { + let pos = rgb("#f28e2b") + let neg = rgb("#76b7b2") + let zero = rgb("#bab0ab") + align(center, stack(dir: ttb, spacing: 0.35cm, + stack(dir: ltr, spacing: 0.08cm, + ..schedule.enumerate().map(((i, task)) => { + let cost = costs.at(task) + let fill = if cost > 0 { + pos.transparentize(70%) + } else if cost < 0 { + neg.transparentize(65%) + } else { + zero.transparentize(65%) + } + stack(dir: ttb, spacing: 0.05cm, + box(width: 1.0cm, height: 0.6cm, fill: fill, stroke: 0.4pt + luma(120), + align(center + horizon, text(8pt, weight: "bold")[$t_#(task + 1)$])), + text(6pt, if cost >= 0 { $+ #cost$ } else { $#cost$ }), + ) + }), + ), + stack(dir: ltr, spacing: 0.08cm, + ..prefix-sums.map(v => { + box(width: 1.0cm, align(center + horizon, text(7pt)[$#v$])) + }), + ), + text(7pt, [prefix sums after each scheduled task]), + )) + }, + caption: [A satisfying schedule for Sequencing to Minimize Maximum Cumulative Cost. Orange boxes add cost, teal boxes release cost, and the displayed prefix sums $(#prefix-sums.map(v => str(v)).join(", "))$ never exceed $K = #bound$.], + ) + ] + ] +} + // Completeness check: warn about problem types in JSON but missing from paper #{ let json-models = { diff --git a/docs/paper/references.bib b/docs/paper/references.bib index 05740229e..b93588716 100644 --- a/docs/paper/references.bib +++ b/docs/paper/references.bib @@ -85,6 +85,28 @@ @article{evenItaiShamir1976 doi = {10.1137/0205048} } +@article{abdelWahabKameda1978, + author = {H. M. Abdel-Wahab and T. Kameda}, + title = {Scheduling to Minimize Maximum Cumulative Cost Subject to Series-Parallel Precedence Constraints}, + journal = {Operations Research}, + volume = {26}, + number = {1}, + pages = {141--158}, + year = {1978}, + doi = {10.1287/opre.26.1.141} +} + +@article{monmaSidney1979, + author = {Clyde L. Monma and Jeffrey B. Sidney}, + title = {Sequencing with Series-Parallel Precedence Constraints}, + journal = {Mathematics of Operations Research}, + volume = {4}, + number = {3}, + pages = {215--224}, + year = {1979}, + doi = {10.1287/moor.4.3.215} +} + @article{glover2019, author = {Fred Glover and Gary Kochenberger and Yu Du}, title = {Quantum Bridge Analytics {I}: a tutorial on formulating and using {QUBO} models}, diff --git a/docs/src/reductions/problem_schemas.json b/docs/src/reductions/problem_schemas.json index 7d60308b8..d922ecca1 100644 --- a/docs/src/reductions/problem_schemas.json +++ b/docs/src/reductions/problem_schemas.json @@ -625,6 +625,27 @@ } ] }, + { + "name": "SequencingToMinimizeMaximumCumulativeCost", + "description": "Schedule tasks with precedence constraints so every cumulative cost prefix stays within a bound", + "fields": [ + { + "name": "costs", + "type_name": "Vec", + "description": "Task costs in schedule order-independent indexing" + }, + { + "name": "precedences", + "type_name": "Vec<(usize, usize)>", + "description": "Precedence pairs (predecessor, successor)" + }, + { + "name": "bound", + "type_name": "i64", + "description": "Upper bound on every cumulative cost prefix" + } + ] + }, { "name": "SetBasis", "description": "Determine whether a collection of sets admits a basis of size k under union", diff --git a/docs/src/reductions/reduction_graph.json b/docs/src/reductions/reduction_graph.json index eb2008453..b2109beca 100644 --- a/docs/src/reductions/reduction_graph.json +++ b/docs/src/reductions/reduction_graph.json @@ -473,6 +473,13 @@ "doc_path": "models/formula/struct.Satisfiability.html", "complexity": "2^num_variables" }, + { + "name": "SequencingToMinimizeMaximumCumulativeCost", + "variant": {}, + "category": "misc", + "doc_path": "models/misc/struct.SequencingToMinimizeMaximumCumulativeCost.html", + "complexity": "factorial(num_tasks)" + }, { "name": "SetBasis", "variant": {}, @@ -592,7 +599,7 @@ }, { "source": 4, - "target": 56, + "target": 57, "overhead": [ { "field": "num_spins", @@ -756,7 +763,7 @@ }, { "source": 21, - "target": 60, + "target": 61, "overhead": [ { "field": "num_elements", @@ -812,7 +819,7 @@ }, { "source": 26, - "target": 56, + "target": 57, "overhead": [ { "field": "num_spins", @@ -1258,7 +1265,7 @@ }, { "source": 50, - "target": 55, + "target": 56, "overhead": [ { "field": "num_spins", @@ -1343,7 +1350,7 @@ "doc_path": "rules/sat_minimumdominatingset/index.html" }, { - "source": 55, + "source": 56, "target": 50, "overhead": [ { @@ -1354,7 +1361,7 @@ "doc_path": "rules/spinglass_qubo/index.html" }, { - "source": 56, + "source": 57, "target": 26, "overhead": [ { @@ -1369,8 +1376,8 @@ "doc_path": "rules/spinglass_maxcut/index.html" }, { - "source": 56, - "target": 55, + "source": 57, + "target": 56, "overhead": [ { "field": "num_spins", @@ -1384,7 +1391,7 @@ "doc_path": "rules/spinglass_casts/index.html" }, { - "source": 61, + "source": 62, "target": 12, "overhead": [ { @@ -1399,7 +1406,7 @@ "doc_path": "rules/travelingsalesman_ilp/index.html" }, { - "source": 61, + "source": 62, "target": 50, "overhead": [ { diff --git a/problemreductions-cli/src/cli.rs b/problemreductions-cli/src/cli.rs index a289e9153..73691301a 100644 --- a/problemreductions-cli/src/cli.rs +++ b/problemreductions-cli/src/cli.rs @@ -246,6 +246,7 @@ Flags by problem type: FVS --arcs [--weights] [--num-vertices] FlowShopScheduling --task-lengths, --deadline [--num-processors] MinimumTardinessSequencing --n, --deadlines [--precedence-pairs] + SequencingToMinimizeMaximumCumulativeCost --costs, --bound [--precedence-pairs] SCS --strings, --bound [--alphabet-size] ILP, CircuitSAT (via reduction only) @@ -421,6 +422,9 @@ pub struct CreateArgs { /// Input strings for LCS (e.g., "ABAC;BACA") or SCS (e.g., "0,1,2;1,2,0") #[arg(long)] pub strings: Option, + /// Task costs for SequencingToMinimizeMaximumCumulativeCost (comma-separated, e.g., "2,-1,3,-2,1,-3") + #[arg(long, allow_hyphen_values = true)] + pub costs: Option, /// Directed arcs for directed graph problems (e.g., 0>1,1>2,2>0) #[arg(long)] pub arcs: Option, diff --git a/problemreductions-cli/src/commands/create.rs b/problemreductions-cli/src/commands/create.rs index a6261ac00..add173363 100644 --- a/problemreductions-cli/src/commands/create.rs +++ b/problemreductions-cli/src/commands/create.rs @@ -11,7 +11,7 @@ use problemreductions::models::graph::{ }; use problemreductions::models::misc::{ BinPacking, FlowShopScheduling, LongestCommonSubsequence, MinimumTardinessSequencing, - PaintShop, ShortestCommonSupersequence, SubsetSum, + PaintShop, SequencingToMinimizeMaximumCumulativeCost, ShortestCommonSupersequence, SubsetSum, }; use problemreductions::prelude::*; use problemreductions::registry::collect_schemas; @@ -69,6 +69,7 @@ fn all_data_flags_empty(args: &CreateArgs) -> bool { && args.bound.is_none() && args.pattern.is_none() && args.strings.is_none() + && args.costs.is_none() && args.arcs.is_none() && args.deadlines.is_none() && args.precedence_pairs.is_none() @@ -171,6 +172,50 @@ fn resolve_rule_example( }) } +fn parse_precedence_pairs(raw: Option<&str>) -> Result> { + raw.filter(|s| !s.is_empty()) + .map(|s| { + s.split(',') + .map(|pair| { + let pair = pair.trim(); + let (pred, succ) = pair.split_once('>').ok_or_else(|| { + anyhow::anyhow!( + "Invalid --precedence-pairs value '{}': expected 'u>v'", + pair + ) + })?; + let pred = pred.trim().parse::().map_err(|_| { + anyhow::anyhow!( + "Invalid --precedence-pairs value '{}': expected 'u>v' with nonnegative integer indices", + pair + ) + })?; + let succ = succ.trim().parse::().map_err(|_| { + anyhow::anyhow!( + "Invalid --precedence-pairs value '{}': expected 'u>v' with nonnegative integer indices", + pair + ) + })?; + Ok((pred, succ)) + }) + .collect() + }) + .unwrap_or_else(|| Ok(vec![])) +} + +fn validate_precedence_pairs(precedences: &[(usize, usize)], num_tasks: usize) -> Result<()> { + for &(pred, succ) in precedences { + anyhow::ensure!( + pred < num_tasks && succ < num_tasks, + "precedence index out of range: ({}, {}) but num_tasks = {}", + pred, + succ, + num_tasks + ); + } + Ok(()) +} + fn create_from_example(args: &CreateArgs, out: &OutputConfig) -> Result<()> { let example_spec = args .example @@ -285,6 +330,9 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str { "SubsetSum" => "--sizes 3,7,1,8,2,4 --target 11", "SetBasis" => "--universe 4 --sets \"0,1;1,2;0,2;0,1,2\" --k 3", "ShortestCommonSupersequence" => "--strings \"0,1,2;1,2,0\" --bound 4", + "SequencingToMinimizeMaximumCumulativeCost" => { + "--costs 2,-1,3,-2,1,-3 --precedence-pairs \"0>2,1>2,1>3,2>4,3>5,4>5\" --bound 4" + } _ => "", } } @@ -1046,39 +1094,14 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> { ) })?; let deadlines: Vec = util::parse_comma_list(deadlines_str)?; - let precedences: Vec<(usize, usize)> = match args.precedence_pairs.as_deref() { - Some(s) if !s.is_empty() => s - .split(',') - .map(|pair| { - let parts: Vec<&str> = pair.trim().split('>').collect(); - anyhow::ensure!( - parts.len() == 2, - "Invalid precedence format '{}', expected 'u>v'", - pair.trim() - ); - Ok(( - parts[0].trim().parse::()?, - parts[1].trim().parse::()?, - )) - }) - .collect::>>()?, - _ => vec![], - }; + let precedences = parse_precedence_pairs(args.precedence_pairs.as_deref())?; anyhow::ensure!( deadlines.len() == num_tasks, "deadlines length ({}) must equal num_tasks ({})", deadlines.len(), num_tasks ); - for &(pred, succ) in &precedences { - anyhow::ensure!( - pred < num_tasks && succ < num_tasks, - "precedence index out of range: ({}, {}) but num_tasks = {}", - pred, - succ, - num_tasks - ); - } + validate_precedence_pairs(&precedences, num_tasks)?; ( ser(MinimumTardinessSequencing::new( num_tasks, @@ -1089,6 +1112,33 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> { ) } + // SequencingToMinimizeMaximumCumulativeCost + "SequencingToMinimizeMaximumCumulativeCost" => { + let costs_str = args.costs.as_deref().ok_or_else(|| { + anyhow::anyhow!( + "SequencingToMinimizeMaximumCumulativeCost requires --costs\n\n\ + Usage: pred create SequencingToMinimizeMaximumCumulativeCost --costs 2,-1,3,-2,1,-3 --precedence-pairs \"0>2,1>2,1>3,2>4,3>5,4>5\" --bound 4" + ) + })?; + let bound = args.bound.ok_or_else(|| { + anyhow::anyhow!( + "SequencingToMinimizeMaximumCumulativeCost requires --bound\n\n\ + Usage: pred create SequencingToMinimizeMaximumCumulativeCost --costs 2,-1,3,-2,1,-3 --precedence-pairs \"0>2,1>2,1>3,2>4,3>5,4>5\" --bound 4" + ) + })?; + let costs: Vec = util::parse_comma_list(costs_str)?; + let precedences = parse_precedence_pairs(args.precedence_pairs.as_deref())?; + validate_precedence_pairs(&precedences, costs.len())?; + ( + ser(SequencingToMinimizeMaximumCumulativeCost::new( + costs, + precedences, + bound, + ))?, + resolved_variant.clone(), + ) + } + // OptimalLinearArrangement — graph + bound "OptimalLinearArrangement" => { let (graph, _) = parse_graph(args).map_err(|e| { diff --git a/problemreductions-cli/tests/cli_tests.rs b/problemreductions-cli/tests/cli_tests.rs index 419e690ad..682333559 100644 --- a/problemreductions-cli/tests/cli_tests.rs +++ b/problemreductions-cli/tests/cli_tests.rs @@ -3479,6 +3479,147 @@ fn test_create_factoring_missing_bits() { ); } +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost() { + let output = pred() + .args([ + "create", + "SequencingToMinimizeMaximumCumulativeCost", + "--costs", + "2,-1,3,-2,1,-3", + "--precedence-pairs", + "0>2,1>2,1>3,2>4,3>5,4>5", + "--bound", + "4", + ]) + .output() + .unwrap(); + assert!( + output.status.success(), + "stderr: {}", + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8(output.stdout).unwrap(); + let json: serde_json::Value = serde_json::from_str(&stdout).unwrap(); + assert_eq!(json["type"], "SequencingToMinimizeMaximumCumulativeCost"); + assert_eq!(json["data"]["costs"], serde_json::json!([2, -1, 3, -2, 1, -3])); + assert_eq!( + json["data"]["precedences"], + serde_json::json!([[0, 2], [1, 2], [1, 3], [2, 4], [3, 5], [4, 5]]) + ); + assert_eq!(json["data"]["bound"], 4); +} + +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost_no_flags_shows_help() { + let output = pred() + .args(["create", "SequencingToMinimizeMaximumCumulativeCost"]) + .output() + .unwrap(); + assert!( + !output.status.success(), + "should exit non-zero when showing help without data flags" + ); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("--costs"), + "expected '--costs' in help output, got: {stderr}" + ); + assert!( + stderr.contains("--bound"), + "expected '--bound' in help output, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost_missing_costs() { + let output = pred() + .args([ + "create", + "SequencingToMinimizeMaximumCumulativeCost", + "--bound", + "4", + ]) + .output() + .unwrap(); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("requires --costs"), + "expected missing --costs message, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost_bad_precedence() { + let output = pred() + .args([ + "create", + "SequencingToMinimizeMaximumCumulativeCost", + "--costs", + "1,-1,2", + "--precedence-pairs", + "0>3", + "--bound", + "2", + ]) + .output() + .unwrap(); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("precedence"), + "expected precedence validation error, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost_invalid_precedence_pair() { + let output = pred() + .args([ + "create", + "SequencingToMinimizeMaximumCumulativeCost", + "--costs", + "1,-1,2", + "--precedence-pairs", + "a>b", + "--bound", + "2", + ]) + .output() + .unwrap(); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + stderr.contains("--precedence-pairs"), + "expected flag-specific precedence parse error, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_to_minimize_maximum_cumulative_cost_allows_negative_values() { + let output = pred() + .args([ + "create", + "SequencingToMinimizeMaximumCumulativeCost", + "--costs", + "-1,2,-3", + "--bound", + "-1", + ]) + .output() + .unwrap(); + assert!( + output.status.success(), + "stderr: {}", + String::from_utf8_lossy(&output.stderr) + ); + let stdout = String::from_utf8(output.stdout).unwrap(); + let json: serde_json::Value = serde_json::from_str(&stdout).unwrap(); + assert_eq!(json["data"]["costs"], serde_json::json!([-1, 2, -3])); + assert_eq!(json["data"]["bound"], -1); +} + // ---- Timeout tests (H3) ---- #[test] diff --git a/src/example_db/fixtures/examples.json b/src/example_db/fixtures/examples.json index 891fe8e70..24ee5155e 100644 --- a/src/example_db/fixtures/examples.json +++ b/src/example_db/fixtures/examples.json @@ -29,6 +29,7 @@ {"problem":"PartitionIntoTriangles","variant":{"graph":"SimpleGraph"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null],[3,4,null],[3,5,null],[4,5,null],[0,3,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}}},"samples":[{"config":[0,0,0,1,1,1],"metric":true}],"optimal":[{"config":[0,0,0,1,1,1],"metric":true},{"config":[1,1,1,0,0,0],"metric":true}]}, {"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-1.0,2.0,0.0],[0.0,-1.0,2.0],[0.0,0.0,-1.0]],"num_vars":3},"samples":[{"config":[1,0,1],"metric":{"Valid":-2.0}}],"optimal":[{"config":[1,0,1],"metric":{"Valid":-2.0}}]}, {"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,2]},{"literals":[-1,3]},{"literals":[-2,-3]}],"num_vars":3},"samples":[{"config":[1,0,1],"metric":true}],"optimal":[{"config":[0,1,0],"metric":true},{"config":[1,0,1],"metric":true}]}, + {"problem":"SequencingToMinimizeMaximumCumulativeCost","variant":{},"instance":{"bound":4,"costs":[2,-1,3,-2,1,-3],"precedences":[[0,2],[1,2],[1,3],[2,4],[3,5],[4,5]]},"samples":[{"config":[1,0,1,0,0,0],"metric":true}],"optimal":[{"config":[0,0,0,0,0,0],"metric":true},{"config":[0,0,1,0,0,0],"metric":true},{"config":[1,0,0,0,0,0],"metric":true},{"config":[1,0,1,0,0,0],"metric":true},{"config":[1,2,0,0,0,0],"metric":true}]}, {"problem":"SetBasis","variant":{},"instance":{"collection":[[0,1],[1,2],[0,2],[0,1,2]],"k":3,"universe_size":4},"samples":[{"config":[1,0,0,0,0,1,0,0,0,0,1,0],"metric":true}],"optimal":[{"config":[0,0,1,0,0,1,0,0,1,0,0,0],"metric":true},{"config":[0,0,1,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,1,0,0,0,0,1,0,1,0,0,0],"metric":true},{"config":[0,1,0,0,1,0,0,0,0,0,1,0],"metric":true},{"config":[0,1,1,0,1,0,1,0,1,1,0,0],"metric":true},{"config":[0,1,1,0,1,1,0,0,1,0,1,0],"metric":true},{"config":[1,0,0,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,0,0,0,1,0,0,0,0,1,0],"metric":true},{"config":[1,0,1,0,0,1,1,0,1,1,0,0],"metric":true},{"config":[1,0,1,0,1,1,0,0,0,1,1,0],"metric":true},{"config":[1,1,0,0,0,1,1,0,1,0,1,0],"metric":true},{"config":[1,1,0,0,1,0,1,0,0,1,1,0],"metric":true}]}, {"problem":"ShortestCommonSupersequence","variant":{},"instance":{"alphabet_size":3,"bound":4,"strings":[[0,1,2],[1,0,2]]},"samples":[{"config":[1,0,1,2],"metric":true}],"optimal":[{"config":[0,1,0,2],"metric":true},{"config":[1,0,1,2],"metric":true}]}, {"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,1,1,1,1,1,1],"fields":[0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[3,4,null],[0,3,null],[1,3,null],[1,4,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}}},"samples":[{"config":[1,0,1,1,0],"metric":{"Valid":-3}}],"optimal":[{"config":[0,0,1,1,0],"metric":{"Valid":-3}},{"config":[0,1,0,0,1],"metric":{"Valid":-3}},{"config":[0,1,0,1,0],"metric":{"Valid":-3}},{"config":[0,1,1,1,0],"metric":{"Valid":-3}},{"config":[1,0,0,0,1],"metric":{"Valid":-3}},{"config":[1,0,1,0,1],"metric":{"Valid":-3}},{"config":[1,0,1,1,0],"metric":{"Valid":-3}},{"config":[1,1,0,0,1],"metric":{"Valid":-3}}]}, diff --git a/src/lib.rs b/src/lib.rs index acbd1d766..7eda81b47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,8 @@ pub mod prelude { }; pub use crate::models::misc::{ BinPacking, Factoring, FlowShopScheduling, Knapsack, LongestCommonSubsequence, - MinimumTardinessSequencing, PaintShop, ShortestCommonSupersequence, SubsetSum, + MinimumTardinessSequencing, PaintShop, SequencingToMinimizeMaximumCumulativeCost, + ShortestCommonSupersequence, SubsetSum, }; pub use crate::models::set::{ ExactCoverBy3Sets, MaximumSetPacking, MinimumSetCovering, SetBasis, diff --git a/src/models/misc/mod.rs b/src/models/misc/mod.rs index cc96aa83e..af0475e4d 100644 --- a/src/models/misc/mod.rs +++ b/src/models/misc/mod.rs @@ -8,6 +8,7 @@ //! - [`LongestCommonSubsequence`]: Longest Common Subsequence //! - [`MinimumTardinessSequencing`]: Minimize tardy tasks in single-machine scheduling //! - [`PaintShop`]: Minimize color switches in paint shop scheduling +//! - [`SequencingToMinimizeMaximumCumulativeCost`]: Keep every cumulative schedule cost prefix under a bound //! - [`ShortestCommonSupersequence`]: Find a common supersequence of bounded length //! - [`SubsetSum`]: Find a subset summing to exactly a target value @@ -18,6 +19,7 @@ mod knapsack; mod longest_common_subsequence; mod minimum_tardiness_sequencing; pub(crate) mod paintshop; +mod sequencing_to_minimize_maximum_cumulative_cost; pub(crate) mod shortest_common_supersequence; mod subset_sum; @@ -28,6 +30,7 @@ pub use knapsack::Knapsack; pub use longest_common_subsequence::LongestCommonSubsequence; pub use minimum_tardiness_sequencing::MinimumTardinessSequencing; pub use paintshop::PaintShop; +pub use sequencing_to_minimize_maximum_cumulative_cost::SequencingToMinimizeMaximumCumulativeCost; pub use shortest_common_supersequence::ShortestCommonSupersequence; pub use subset_sum::SubsetSum; @@ -38,5 +41,6 @@ pub(crate) fn canonical_model_example_specs() -> Vec", description: "Task costs in schedule order-independent indexing" }, + FieldInfo { name: "precedences", type_name: "Vec<(usize, usize)>", description: "Precedence pairs (predecessor, successor)" }, + FieldInfo { name: "bound", type_name: "i64", description: "Upper bound on every cumulative cost prefix" }, + ], + } +} + +/// Sequencing to Minimize Maximum Cumulative Cost. +/// +/// Given a set of tasks `T`, a cost `c(t) in Z` for each task, a partial order +/// on the tasks, and a bound `K`, determine whether there exists a schedule that +/// respects the precedences and whose running cumulative cost never exceeds `K`. +/// +/// # Representation +/// +/// Configurations use Lehmer-code dimensions `[n, n-1, ..., 1]` to encode a +/// permutation of the task indices. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SequencingToMinimizeMaximumCumulativeCost { + costs: Vec, + precedences: Vec<(usize, usize)>, + bound: i64, +} + +impl SequencingToMinimizeMaximumCumulativeCost { + /// Create a new instance. + /// + /// # Panics + /// + /// Panics if any precedence endpoint is out of range. + pub fn new(costs: Vec, precedences: Vec<(usize, usize)>, bound: i64) -> Self { + let num_tasks = costs.len(); + for &(pred, succ) in &precedences { + assert!( + pred < num_tasks, + "predecessor index {} out of range (num_tasks = {})", + pred, + num_tasks + ); + assert!( + succ < num_tasks, + "successor index {} out of range (num_tasks = {})", + succ, + num_tasks + ); + } + Self { + costs, + precedences, + bound, + } + } + + /// Return the task costs. + pub fn costs(&self) -> &[i64] { + &self.costs + } + + /// Return the precedence constraints. + pub fn precedences(&self) -> &[(usize, usize)] { + &self.precedences + } + + /// Return the cumulative-cost bound. + pub fn bound(&self) -> i64 { + self.bound + } + + /// Return the number of tasks. + pub fn num_tasks(&self) -> usize { + self.costs.len() + } + + /// Return the number of precedence constraints. + pub fn num_precedences(&self) -> usize { + self.precedences.len() + } + + fn decode_schedule(&self, config: &[usize]) -> Option> { + let n = self.num_tasks(); + if config.len() != n { + return None; + } + + let mut available: Vec = (0..n).collect(); + let mut schedule = Vec::with_capacity(n); + for &digit in config { + if digit >= available.len() { + return None; + } + schedule.push(available.remove(digit)); + } + Some(schedule) + } +} + +impl Problem for SequencingToMinimizeMaximumCumulativeCost { + const NAME: &'static str = "SequencingToMinimizeMaximumCumulativeCost"; + type Metric = bool; + + fn variant() -> Vec<(&'static str, &'static str)> { + crate::variant_params![] + } + + fn dims(&self) -> Vec { + let n = self.num_tasks(); + (0..n).rev().map(|i| i + 1).collect() + } + + fn evaluate(&self, config: &[usize]) -> bool { + let Some(schedule) = self.decode_schedule(config) else { + return false; + }; + + let mut positions = vec![0usize; self.num_tasks()]; + for (position, &task) in schedule.iter().enumerate() { + positions[task] = position; + } + for &(pred, succ) in &self.precedences { + if positions[pred] >= positions[succ] { + return false; + } + } + + let mut cumulative = 0i64; + for &task in &schedule { + cumulative += self.costs[task]; + if cumulative > self.bound { + return false; + } + } + true + } +} + +impl SatisfactionProblem for SequencingToMinimizeMaximumCumulativeCost {} + +crate::declare_variants! { + default sat SequencingToMinimizeMaximumCumulativeCost => "factorial(num_tasks)", +} + +#[cfg(feature = "example-db")] +pub(crate) fn canonical_model_example_specs() -> Vec { + vec![crate::example_db::specs::ModelExampleSpec { + id: "sequencing_to_minimize_maximum_cumulative_cost", + build: || { + let problem = SequencingToMinimizeMaximumCumulativeCost::new( + vec![2, -1, 3, -2, 1, -3], + vec![(0, 2), (1, 2), (1, 3), (2, 4), (3, 5), (4, 5)], + 4, + ); + crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 1, 0, 0, 0]]) + }, + }] +} + +#[cfg(test)] +#[path = "../../unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs"] +mod tests; diff --git a/src/models/mod.rs b/src/models/mod.rs index 3031a2d9a..2213c7217 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -21,6 +21,7 @@ pub use graph::{ }; pub use misc::{ BinPacking, Factoring, FlowShopScheduling, Knapsack, LongestCommonSubsequence, - MinimumTardinessSequencing, PaintShop, ShortestCommonSupersequence, SubsetSum, + MinimumTardinessSequencing, PaintShop, SequencingToMinimizeMaximumCumulativeCost, + ShortestCommonSupersequence, SubsetSum, }; pub use set::{ExactCoverBy3Sets, MaximumSetPacking, MinimumSetCovering, SetBasis}; diff --git a/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs b/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs new file mode 100644 index 000000000..aec84aadb --- /dev/null +++ b/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs @@ -0,0 +1,129 @@ +use super::*; +use crate::solvers::{BruteForce, Solver}; +use crate::traits::Problem; + +fn issue_example(bound: i64) -> SequencingToMinimizeMaximumCumulativeCost { + SequencingToMinimizeMaximumCumulativeCost::new( + vec![2, -1, 3, -2, 1, -3], + vec![(0, 2), (1, 2), (1, 3), (2, 4), (3, 5), (4, 5)], + bound, + ) +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_creation() { + let problem = issue_example(4); + assert_eq!(problem.costs(), &[2, -1, 3, -2, 1, -3]); + assert_eq!( + problem.precedences(), + &[(0, 2), (1, 2), (1, 3), (2, 4), (3, 5), (4, 5)] + ); + assert_eq!(problem.bound(), 4); + assert_eq!(problem.num_tasks(), 6); + assert_eq!(problem.num_precedences(), 6); + assert_eq!(problem.dims(), vec![6, 5, 4, 3, 2, 1]); + assert_eq!( + ::NAME, + "SequencingToMinimizeMaximumCumulativeCost" + ); + assert_eq!( + ::variant(), + vec![] + ); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_evaluate_satisfying_issue_order() { + let problem = issue_example(4); + + // Task order [1, 0, 3, 2, 4, 5]: + // available [0,1,2,3,4,5] -> pick 1 + // available [0,2,3,4,5] -> pick 0 + // available [2,3,4,5] -> pick 1 + // available [2,4,5] -> pick 0 + // available [4,5] -> pick 0 + // available [5] -> pick 0 + let config = vec![1, 0, 1, 0, 0, 0]; + assert!(problem.evaluate(&config)); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_evaluate_tight_bound() { + let problem = issue_example(3); + + // Identity order [0,1,2,3,4,5] reaches prefix sums 2,1,4,... and should fail for K = 3. + assert!(!problem.evaluate(&[0, 0, 0, 0, 0, 0])); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_precedence_violation() { + let problem = issue_example(10); + + // Task order [2, 0, 1, 3, 4, 5] violates precedence 0 -> 2. + assert!(!problem.evaluate(&[2, 0, 0, 0, 0, 0])); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_invalid_config() { + let problem = issue_example(4); + assert!(!problem.evaluate(&[6, 0, 0, 0, 0, 0])); + assert!(!problem.evaluate(&[1, 0, 1, 0, 0])); + assert!(!problem.evaluate(&[1, 0, 1, 0, 0, 0, 0])); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_brute_force_solver() { + let problem = issue_example(4); + let solver = BruteForce::new(); + let solution = solver + .find_satisfying(&problem) + .expect("should find a satisfying schedule"); + assert!(problem.evaluate(&solution)); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_unsatisfiable_cycle() { + let problem = SequencingToMinimizeMaximumCumulativeCost::new( + vec![1, -1, 2], + vec![(0, 1), (1, 2), (2, 0)], + 10, + ); + let solver = BruteForce::new(); + assert!(solver.find_satisfying(&problem).is_none()); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_paper_example() { + let problem = issue_example(4); + let sample_config = vec![1, 0, 1, 0, 0, 0]; + assert!(problem.evaluate(&sample_config)); + + let satisfying = BruteForce::new().find_all_satisfying(&problem); + assert_eq!(satisfying.len(), 5); + assert!(satisfying.iter().any(|config| config == &sample_config)); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_empty_instance() { + let problem = SequencingToMinimizeMaximumCumulativeCost::new(vec![], vec![], 0); + assert_eq!(problem.num_tasks(), 0); + assert_eq!(problem.dims(), Vec::::new()); + assert!(problem.evaluate(&[])); +} + +#[test] +#[should_panic(expected = "predecessor index 4 out of range")] +fn test_sequencing_to_minimize_maximum_cumulative_cost_invalid_precedence_endpoint() { + SequencingToMinimizeMaximumCumulativeCost::new(vec![1, -1, 2], vec![(4, 0)], 2); +} + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_serialization() { + let problem = issue_example(4); + let json = serde_json::to_value(&problem).unwrap(); + let restored: SequencingToMinimizeMaximumCumulativeCost = + serde_json::from_value(json).unwrap(); + assert_eq!(restored.costs(), problem.costs()); + assert_eq!(restored.precedences(), problem.precedences()); + assert_eq!(restored.bound(), problem.bound()); +} diff --git a/src/unit_tests/trait_consistency.rs b/src/unit_tests/trait_consistency.rs index e5117e24d..d43285884 100644 --- a/src/unit_tests/trait_consistency.rs +++ b/src/unit_tests/trait_consistency.rs @@ -165,6 +165,10 @@ fn test_all_problems_implement_trait_correctly() { &MinimumTardinessSequencing::new(3, vec![2, 3, 1], vec![(0, 2)]), "MinimumTardinessSequencing", ); + check_problem_trait( + &SequencingToMinimizeMaximumCumulativeCost::new(vec![1, -1, 2], vec![(0, 2)], 2), + "SequencingToMinimizeMaximumCumulativeCost", + ); } #[test] From f3f5187b7dae6b2f8884a2cda45a2ac9e6dc4bb8 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Mon, 16 Mar 2026 23:08:45 +0800 Subject: [PATCH 3/7] chore: remove plan file after implementation --- ...ing-to-minimize-maximum-cumulative-cost.md | 238 ------------------ 1 file changed, 238 deletions(-) delete mode 100644 docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md diff --git a/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md b/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md deleted file mode 100644 index f6d38c549..000000000 --- a/docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md +++ /dev/null @@ -1,238 +0,0 @@ -# Sequencing to Minimize Maximum Cumulative Cost Implementation Plan - -> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. - -**Goal:** Add the `SequencingToMinimizeMaximumCumulativeCost` decision model, its registry/CLI/example-db/test wiring, and the matching paper entry for issue #500. - -**Architecture:** Implement this as a `misc` satisfaction problem with constructor-facing fields `costs: Vec`, `precedences: Vec<(usize, usize)>`, and `bound: i64`. Encode schedules with Lehmer-code dimensions `[n, n-1, ..., 1]`, decode to a permutation during evaluation, reject precedence violations, and accept exactly those schedules whose running cumulative cost never exceeds `bound`. - -**Tech Stack:** Rust library crate, registry inventory metadata, clap-based CLI creation flow, example-db canonical examples, Typst paper docs. - ---- - -## Batch 1: Model, registration, CLI, tests - -### Task 1: Add the core model and its failing tests - -**Files:** -- Create: `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` -- Create: `src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` -- Modify: `src/models/misc/mod.rs` -- Modify: `src/models/mod.rs` -- Modify: `src/lib.rs` - -**Step 1: Write the failing tests** - -Add tests that pin down the intended representation and semantics: -- construction/getters: `costs()`, `precedences()`, `bound()`, `num_tasks()`, `num_precedences()` -- `dims()` uses Lehmer code (`[n, n-1, ..., 1]`) -- `evaluate()` accepts the issue’s feasible schedule and rejects: - - a Lehmer digit outside its domain - - a precedence-violating schedule - - a schedule whose cumulative maximum exceeds `bound` -- brute-force finds a satisfying schedule for the paper/issue example and finds none for a cyclic-precedence or too-tight instance -- serde round-trip - -Use the issue example as the main satisfaction instance: -- `costs = [2, -1, 3, -2, 1, -3]` -- `precedences = [(0, 2), (1, 2), (1, 3), (2, 4), (3, 5), (4, 5)]` -- `bound = 4` -- schedule `t2, t1, t4, t3, t5, t6` (0-indexed `[1, 0, 3, 2, 4, 5]`) should be encoded to its Lehmer form and asserted satisfying - -**Step 2: Run the tests to verify they fail** - -Run: `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` - -Expected: failures because the model file and test module link do not exist yet. - -**Step 3: Write the minimal model implementation** - -Implement `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` with: -- `inventory::submit!` schema metadata -- `#[derive(Debug, Clone, Serialize, Deserialize)]` model struct -- constructor validations: - - `costs.len()` defines `num_tasks` - - every precedence endpoint is in range -- getters: `costs()`, `precedences()`, `bound()`, `num_tasks()`, `num_precedences()` -- `Problem` impl with `Metric = bool` -- Lehmer-code `dims()` -- permutation decoder helper -- cumulative-cost checker over decoded schedule -- `impl SatisfactionProblem` -- `crate::declare_variants! { default sat ... => "factorial(num_tasks)" }` -- test-module link at file end - -Register the model in: -- `src/models/misc/mod.rs` -- `src/models/mod.rs` -- `src/lib.rs` - -**Step 4: Run the tests to verify they pass** - -Run: `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` - -Expected: the new model tests pass. - -**Step 5: Commit** - -```bash -git add src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ - src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ - src/models/misc/mod.rs src/models/mod.rs src/lib.rs -git commit -m "Add SequencingToMinimizeMaximumCumulativeCost model" -``` - -### Task 2: Wire example-db and trait consistency - -**Files:** -- Modify: `src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs` -- Modify: `src/models/misc/mod.rs` -- Modify: `src/unit_tests/trait_consistency.rs` - -**Step 1: Write the failing tests** - -Add: -- a canonical model example builder in the model file under `#[cfg(feature = "example-db")]` -- a `trait_consistency` entry for the new model -- a paper/example consistency test in the model test file that: - - constructs the exact issue example - - checks the documented satisfying Lehmer code - - checks the brute-force satisfying set is non-empty and includes a satisfying schedule - -**Step 2: Run the focused tests** - -Run: `cargo test trait_consistency sequencing_to_minimize_maximum_cumulative_cost --lib` - -Expected: failures until the example-db hook and consistency wiring are added. - -**Step 3: Implement the wiring** - -Add the canonical example spec in the model file and extend `src/models/misc/mod.rs` so the misc example registry includes it. Update `src/unit_tests/trait_consistency.rs` with `check_problem_trait(...)` for a small instance. - -**Step 4: Re-run the focused tests** - -Run: `cargo test trait_consistency sequencing_to_minimize_maximum_cumulative_cost --lib` - -Expected: passing tests. - -**Step 5: Commit** - -```bash -git add src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs \ - src/models/misc/mod.rs \ - src/unit_tests/trait_consistency.rs -git commit -m "Wire examples and trait checks for issue #500" -``` - -### Task 3: Add CLI create support - -**Files:** -- Modify: `problemreductions-cli/src/cli.rs` -- Modify: `problemreductions-cli/src/commands/create.rs` - -**Step 1: Write the failing CLI tests** - -Add or extend `pred create` tests covering: -- explicit creation with `--costs`, `--bound`, and optional `--precedence-pairs` -- validation that precedence endpoints are within range -- omission of `--precedence-pairs` for an unconstrained instance - -Prefer constructor-facing CLI fields: -- `--costs` -- `--bound` -- `--precedence-pairs` - -**Step 2: Run the CLI tests to verify they fail** - -Run: `cargo test create:: sequencing_to_minimize_maximum_cumulative_cost` - -Expected: failures because the new flags/help/match arm do not exist yet. - -**Step 3: Implement CLI support** - -Update: -- `CreateArgs` with a `costs` string flag for this problem -- `all_data_flags_empty()` to include the new flag -- the create help table with a `SequencingToMinimizeMaximumCumulativeCost --costs, --bound [--precedence-pairs]` entry -- `problem_examples()` / usage text in `create.rs` -- the main `create()` match to parse `i64` costs, reuse `--precedence-pairs`, validate endpoint ranges against `costs.len()`, and serialize the new model - -**Step 4: Re-run the CLI tests** - -Run: `cargo test create:: sequencing_to_minimize_maximum_cumulative_cost` - -Expected: passing CLI tests. - -**Step 5: Commit** - -```bash -git add problemreductions-cli/src/cli.rs problemreductions-cli/src/commands/create.rs -git commit -m "Add pred create support for issue #500" -``` - -## Batch 2: Paper entry - -### Task 4: Document the model in the paper - -**Files:** -- Modify: `docs/paper/reductions.typ` -- Modify: `docs/paper/references.bib` (only if one of the needed citations is missing) - -**Step 1: Write the paper changes** - -Add: -- display-name entry for `SequencingToMinimizeMaximumCumulativeCost` -- `problem-def("SequencingToMinimizeMaximumCumulativeCost")` -- background and algorithm notes citing: - - Garey & Johnson A5 SS7 - - Abdel-Wahab (1976) for NP-completeness / register-sufficiency connection - - Abdel-Wahab & Kameda (1978) for the series-parallel polynomial case - - Monma & Sidney (1979), correcting the issue’s wrong year -- a worked example using the same 6-task instance as the model tests -- explicit explanation that the example schedule keeps the running cumulative cost at most `K = 4` - -Keep the paper example aligned with the canonical example/tested Lehmer code from Batch 1. - -**Step 2: Build the paper** - -Run: `make paper` - -Expected: Typst compiles successfully and the new `problem-def` renders without missing display-name or example-db references. - -**Step 3: Commit** - -```bash -git add docs/paper/reductions.typ -git commit -m "Document issue #500 in the paper" -``` - -## Final verification and review - -### Task 5: Full verification - -**Files:** -- Modify as needed from verification fixes - -**Step 1: Run repo verification** - -Run: -- `cargo test sequencing_to_minimize_maximum_cumulative_cost --lib` -- `cargo test trait_consistency --lib` -- `cargo test create:: --package problemreductions-cli` -- `make test` -- `make clippy` - -Expected: all commands pass. - -**Step 2: Run implementation review** - -Run the repo-local review skill after Batch 1 and again after any verification-driven fixes if needed. Auto-fix structural issues before pushing. - -**Step 3: Clean up the plan file after implementation** - -When the code and docs are complete, remove this plan file before the final implementation push: - -```bash -git rm docs/plans/2026-03-16-sequencing-to-minimize-maximum-cumulative-cost.md -git commit -m "chore: remove issue #500 plan file" -``` From 8e2eea0368332927623f1b92cf7eb8873ed3c551 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 17 Mar 2026 02:45:54 +0800 Subject: [PATCH 4/7] fix: dedupe merged model fixtures --- src/example_db/fixtures/examples.json | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/example_db/fixtures/examples.json b/src/example_db/fixtures/examples.json index cec61f1fe..baa53956f 100644 --- a/src/example_db/fixtures/examples.json +++ b/src/example_db/fixtures/examples.json @@ -34,8 +34,6 @@ {"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,2]},{"literals":[-1,3]},{"literals":[-2,-3]}],"num_vars":3},"samples":[{"config":[1,0,1],"metric":true}],"optimal":[{"config":[0,1,0],"metric":true},{"config":[1,0,1],"metric":true}]}, {"problem":"SequencingToMinimizeMaximumCumulativeCost","variant":{},"instance":{"bound":4,"costs":[2,-1,3,-2,1,-3],"precedences":[[0,2],[1,2],[1,3],[2,4],[3,5],[4,5]]},"samples":[{"config":[1,0,1,0,0,0],"metric":true}],"optimal":[{"config":[0,0,0,0,0,0],"metric":true},{"config":[0,0,1,0,0,0],"metric":true},{"config":[1,0,0,0,0,0],"metric":true},{"config":[1,0,1,0,0,0],"metric":true},{"config":[1,2,0,0,0,0],"metric":true}]}, {"problem":"SequencingWithinIntervals","variant":{},"instance":{"deadlines":[11,11,11,11,6],"lengths":[3,1,2,4,1],"release_times":[0,0,0,0,5]},"samples":[{"config":[0,6,3,7,0],"metric":true}],"optimal":[{"config":[0,6,3,7,0],"metric":true},{"config":[0,10,3,6,0],"metric":true},{"config":[2,6,0,7,0],"metric":true},{"config":[2,10,0,6,0],"metric":true},{"config":[6,0,9,1,0],"metric":true},{"config":[6,4,9,0,0],"metric":true},{"config":[8,0,6,1,0],"metric":true},{"config":[8,4,6,0,0],"metric":true}]}, - {"problem":"SequencingToMinimizeMaximumCumulativeCost","variant":{},"instance":{"bound":4,"costs":[2,-1,3,-2,1,-3],"precedences":[[0,2],[1,2],[1,3],[2,4],[3,5],[4,5]]},"samples":[{"config":[1,0,1,0,0,0],"metric":true}],"optimal":[{"config":[0,0,0,0,0,0],"metric":true},{"config":[0,0,1,0,0,0],"metric":true},{"config":[1,0,0,0,0,0],"metric":true},{"config":[1,0,1,0,0,0],"metric":true},{"config":[1,2,0,0,0,0],"metric":true}]}, - {"problem":"SequencingWithinIntervals","variant":{},"instance":{"deadlines":[11,11,11,11,6],"lengths":[3,1,2,4,1],"release_times":[0,0,0,0,5]},"samples":[{"config":[0,6,3,7,0],"metric":true}],"optimal":[{"config":[0,6,3,7,0],"metric":true},{"config":[0,10,3,6,0],"metric":true},{"config":[2,6,0,7,0],"metric":true},{"config":[2,10,0,6,0],"metric":true},{"config":[6,0,9,1,0],"metric":true},{"config":[6,4,9,0,0],"metric":true},{"config":[8,0,6,1,0],"metric":true},{"config":[8,4,6,0,0],"metric":true}]}, {"problem":"SetBasis","variant":{},"instance":{"collection":[[0,1],[1,2],[0,2],[0,1,2]],"k":3,"universe_size":4},"samples":[{"config":[1,0,0,0,0,1,0,0,0,0,1,0],"metric":true}],"optimal":[{"config":[0,0,1,0,0,1,0,0,1,0,0,0],"metric":true},{"config":[0,0,1,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,1,0,0,0,0,1,0,1,0,0,0],"metric":true},{"config":[0,1,0,0,1,0,0,0,0,0,1,0],"metric":true},{"config":[0,1,1,0,1,0,1,0,1,1,0,0],"metric":true},{"config":[0,1,1,0,1,1,0,0,1,0,1,0],"metric":true},{"config":[1,0,0,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,0,0,0,1,0,0,0,0,1,0],"metric":true},{"config":[1,0,1,0,0,1,1,0,1,1,0,0],"metric":true},{"config":[1,0,1,0,1,1,0,0,0,1,1,0],"metric":true},{"config":[1,1,0,0,0,1,1,0,1,0,1,0],"metric":true},{"config":[1,1,0,0,1,0,1,0,0,1,1,0],"metric":true}]}, {"problem":"ShortestCommonSupersequence","variant":{},"instance":{"alphabet_size":3,"bound":4,"strings":[[0,1,2],[1,0,2]]},"samples":[{"config":[1,0,1,2],"metric":true}],"optimal":[{"config":[0,1,0,2],"metric":true},{"config":[1,0,1,2],"metric":true}]}, {"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,1,1,1,1,1,1],"fields":[0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[3,4,null],[0,3,null],[1,3,null],[1,4,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}}},"samples":[{"config":[1,0,1,1,0],"metric":{"Valid":-3}}],"optimal":[{"config":[0,0,1,1,0],"metric":{"Valid":-3}},{"config":[0,1,0,0,1],"metric":{"Valid":-3}},{"config":[0,1,0,1,0],"metric":{"Valid":-3}},{"config":[0,1,1,1,0],"metric":{"Valid":-3}},{"config":[1,0,0,0,1],"metric":{"Valid":-3}},{"config":[1,0,1,0,1],"metric":{"Valid":-3}},{"config":[1,0,1,1,0],"metric":{"Valid":-3}},{"config":[1,1,0,0,1],"metric":{"Valid":-3}}]}, @@ -53,18 +51,18 @@ {"source":{"problem":"KColoring","variant":{"graph":"SimpleGraph","k":"KN"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"num_colors":3}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[1,1.0],[2,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[3,1.0],[4,1.0],[5,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[6,1.0],[7,1.0],[8,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[9,1.0],[10,1.0],[11,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[12,1.0],[13,1.0],[14,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[15,1.0],[16,1.0],[17,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[18,1.0],[19,1.0],[20,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[21,1.0],[22,1.0],[23,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[24,1.0],[25,1.0],[26,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[27,1.0],[28,1.0],[29,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[3,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[13,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[14,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[15,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[16,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[17,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[3,1.0],[6,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[4,1.0],[7,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0],[8,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[3,1.0],[18,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[4,1.0],[19,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0],[20,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[6,1.0],[9,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[7,1.0],[10,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[11,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[6,1.0],[21,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[7,1.0],[22,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[23,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[9,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[10,1.0],[13,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[11,1.0],[14,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[9,1.0],[24,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[10,1.0],[25,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[11,1.0],[26,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[12,1.0],[27,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[13,1.0],[28,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[14,1.0],[29,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[15,1.0],[21,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[16,1.0],[22,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[17,1.0],[23,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[15,1.0],[24,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[16,1.0],[25,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[17,1.0],[26,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[18,1.0],[24,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[19,1.0],[25,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[20,1.0],[26,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[18,1.0],[27,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[19,1.0],[28,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[20,1.0],[29,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[21,1.0],[27,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[22,1.0],[28,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[23,1.0],[29,1.0]]}],"num_vars":30,"objective":[],"sense":"Minimize"}},"solutions":[{"source_config":[0,2,0,1,2,1,1,2,0,0],"target_config":[1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,1,0,0]}]}, {"source":{"problem":"KColoring","variant":{"graph":"SimpleGraph","k":"KN"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,3,null],[2,3,null],[2,4,null],[3,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"num_colors":3}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-6.0,12.0,12.0,3.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,-6.0,12.0,0.0,3.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,-6.0,0.0,0.0,3.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,-6.0,12.0,12.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,-6.0,12.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,-6.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0,12.0,3.0,0.0,0.0,3.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0,0.0,3.0,0.0,0.0,3.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,0.0,0.0,3.0,0.0,0.0,3.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0,12.0,3.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0,0.0,3.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,0.0,0.0,3.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0,12.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,12.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0]],"num_vars":15}},"solutions":[{"source_config":[1,2,2,1,0],"target_config":[0,1,0,0,0,1,0,0,1,0,1,0,1,0,0]}]}, {"source":{"problem":"KSatisfiability","variant":{"k":"K2"},"instance":{"clauses":[{"literals":[1,2]},{"literals":[-1,3]},{"literals":[-2,4]},{"literals":[-3,-4]}],"num_vars":4}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[0.0,1.0,-1.0,0.0],[0.0,0.0,0.0,-1.0],[0.0,0.0,0.0,1.0],[0.0,0.0,0.0,0.0]],"num_vars":4}},"solutions":[{"source_config":[0,1,0,1],"target_config":[0,1,0,1]}]}, - {"source":{"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[-2,3,-5]},{"literals":[1,-3,5]},{"literals":[-1,-2,4]},{"literals":[3,-4,-5]}],"num_vars":5}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[0.0,4.0,-4.0,0.0,0.0,4.0,-4.0,0.0,0.0,4.0,-4.0,0.0],[0.0,0.0,-2.0,-2.0,0.0,4.0,0.0,4.0,-4.0,0.0,-4.0,0.0],[0.0,0.0,2.0,-2.0,0.0,1.0,4.0,0.0,4.0,-4.0,0.0,4.0],[0.0,0.0,0.0,4.0,0.0,0.0,-1.0,-4.0,0.0,0.0,-1.0,-4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,1.0,-1.0,0.0,1.0],[0.0,0.0,0.0,0.0,0.0,-2.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0]],"num_vars":12}},"solutions":[{"source_config":[0,0,0,0,0],"target_config":[0,0,0,0,0,1,0,0,0,0,0,0]}]}, + {"source":{"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[-2,3,-5]},{"literals":[1,-3,5]},{"literals":[-1,-2,4]},{"literals":[3,-4,-5]}],"num_vars":5}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[0.0,4.0,-4.0,0.0,0.0,4.0,-4.0,0.0,0.0,4.0,-4.0,0.0],[0.0,0.0,-2.0,-2.0,0.0,4.0,0.0,4.0,-4.0,0.0,-4.0,0.0],[0.0,0.0,2.0,-2.0,0.0,1.0,4.0,0.0,4.0,-4.0,0.0,4.0],[0.0,0.0,0.0,4.0,0.0,0.0,-1.0,-4.0,0.0,0.0,-1.0,-4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,1.0,-1.0,0.0,1.0],[0.0,0.0,0.0,0.0,0.0,-2.0,0.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0]],"num_vars":12}},"solutions":[{"source_config":[1,1,1,1,1],"target_config":[1,1,1,1,1,0,0,0,0,0,1,0]}]}, {"source":{"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,2,3]},{"literals":[-1,-2,3]}],"num_vars":3}},"target":{"problem":"SubsetSum","variant":{},"instance":{"sizes":["10010","10001","1010","1001","111","100","10","20","1","2"],"target":"11144"}},"solutions":[{"source_config":[0,0,1],"target_config":[0,1,0,1,1,0,1,1,1,0]}]}, {"source":{"problem":"KSatisfiability","variant":{"k":"KN"},"instance":{"clauses":[{"literals":[1,-2,3]},{"literals":[-1,3,4]},{"literals":[2,-3,-4]}],"num_vars":4}},"target":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,-2,3]},{"literals":[-1,3,4]},{"literals":[2,-3,-4]}],"num_vars":4}},"solutions":[{"source_config":[1,1,1,0],"target_config":[1,1,1,0]}]}, {"source":{"problem":"Knapsack","variant":{},"instance":{"capacity":7,"values":[3,4,5,7],"weights":[2,3,4,5]}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-483.0,240.0,320.0,400.0,80.0,160.0,320.0],[0.0,-664.0,480.0,600.0,120.0,240.0,480.0],[0.0,0.0,-805.0,800.0,160.0,320.0,640.0],[0.0,0.0,0.0,-907.0,200.0,400.0,800.0],[0.0,0.0,0.0,0.0,-260.0,80.0,160.0],[0.0,0.0,0.0,0.0,0.0,-480.0,320.0],[0.0,0.0,0.0,0.0,0.0,0.0,-800.0]],"num_vars":7}},"solutions":[{"source_config":[1,0,0,1],"target_config":[1,0,0,1,0,0,0]}]}, {"source":{"problem":"LongestCommonSubsequence","variant":{},"instance":{"strings":[[65,66,65,67],[66,65,67,65]]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[1,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[3,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[3,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[3,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[4,1.0],[5,1.0]]}],"num_vars":6,"objective":[[0,1.0],[1,1.0],[2,1.0],[3,1.0],[4,1.0],[5,1.0]],"sense":"Maximize"}},"solutions":[{"source_config":[0,1,1,1],"target_config":[0,0,1,1,0,1]}]}, - {"source":{"problem":"MaxCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"fields":[0,0,0,0,0,0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[0,1,0,1,0,1,0,0,0,1],"target_config":[0,1,0,1,0,1,0,0,0,1]}]}, + {"source":{"problem":"MaxCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"fields":[0,0,0,0,0,0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[1,0,1,0,0,0,0,0,1,1],"target_config":[1,0,1,0,0,0,0,0,1,1]}]}, {"source":{"problem":"MaximumClique","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[0,3,null],[0,4,null],[1,2,null],[1,3,null],[1,5,null],[2,4,null],[2,5,null],[3,4,null],[3,5,null],[4,5,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[3,1.0]]}],"num_vars":6,"objective":[[0,1.0],[1,1.0],[2,1.0],[3,1.0],[4,1.0],[5,1.0]],"sense":"Maximize"}},"solutions":[{"source_config":[1,1,1,0,0,0],"target_config":[1,1,1,0,0,0]}]}, {"source":{"problem":"MaximumClique","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null]],"node_holes":[],"nodes":[null,null,null,null]}},"weights":[1,1,1,1]}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,2,null],[0,3,null],[1,3,null]],"node_holes":[],"nodes":[null,null,null,null]}},"weights":[1,1,1,1]}},"solutions":[{"source_config":[0,1,1,0],"target_config":[0,1,1,0]}]}, - {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"One"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumSetPacking","variant":{"weight":"One"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,0,1,0,0,1,1,0,0],"target_config":[1,0,0,1,0,0,1,1,0,0]}]}, + {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"One"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumSetPacking","variant":{"weight":"One"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,1,0,0,0,0,0,1,1],"target_config":[1,0,1,0,0,0,0,0,1,1]}]}, {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"weights":[1,1,1,1,1]}},"target":{"problem":"MaximumClique","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,2,null],[0,3,null],[0,4,null],[1,3,null],[1,4,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"weights":[1,1,1,1,1]}},"solutions":[{"source_config":[1,0,1,0,1],"target_config":[1,0,1,0,1]}]}, - {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,0,1,0,0,1,1,0,0],"target_config":[1,0,0,1,0,0,1,1,0,0]}]}, - {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,0,1,0,0,1,1,0,0],"target_config":[0,1,1,0,1,1,0,0,1,1]}]}, + {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,1,0,0,0,0,0,1,1],"target_config":[1,0,1,0,0,0,0,0,1,1]}]}, + {"source":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,1,0,0,0,0,0,1,1],"target_config":[0,1,0,1,1,1,1,1,0,0]}]}, {"source":{"problem":"MaximumMatching","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[1,1.0],[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[3,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[3,1.0],[5,1.0],[6,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0],[7,1.0],[8,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[7,1.0],[9,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[10,1.0],[11,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[4,1.0],[12,1.0],[13,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[6,1.0],[10,1.0],[14,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[11,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[9,1.0],[13,1.0],[14,1.0]]}],"num_vars":15,"objective":[[0,1.0],[1,1.0],[2,1.0],[3,1.0],[4,1.0],[5,1.0],[6,1.0],[7,1.0],[8,1.0],[9,1.0],[10,1.0],[11,1.0],[12,1.0],[13,1.0],[14,1.0]],"sense":"Maximize"}},"solutions":[{"source_config":[0,0,1,1,0,0,0,1,0,0,0,0,1,0,1],"target_config":[0,0,1,1,0,0,0,1,0,0,0,0,1,0,1]}]}, {"source":{"problem":"MaximumMatching","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1],[0,4],[0,5],[1,2],[1,6],[2,3],[2,7],[3,4],[3,8],[4,9],[5,7],[5,8],[6,8],[6,9],[7,9]],"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[0,0,1,1,0,0,0,1,0,0,0,0,1,0,1],"target_config":[0,0,1,1,0,0,0,1,0,0,0,0,1,0,1]}]}, {"source":{"problem":"MaximumSetPacking","variant":{"weight":"One"},"instance":{"sets":[[0,1,2],[2,3],[4,5,6],[1,5,7],[3,6]],"weights":[1,1,1,1,1]}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"One"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,3,null],[1,4,null],[2,3,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"weights":[1,1,1,1,1]}},"solutions":[{"source_config":[1,0,0,0,1],"target_config":[1,0,0,0,1]}]}, @@ -73,18 +71,18 @@ {"source":{"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[2,3],[4,5,6],[1,5,7],[3,6]],"weights":[1,1,1,1,1]}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,3,null],[1,4,null],[2,3,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"weights":[1,1,1,1,1]}},"solutions":[{"source_config":[1,0,0,0,1],"target_config":[1,0,0,0,1]}]}, {"source":{"problem":"MinimumDominatingSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Ge","rhs":1.0,"terms":[[0,1.0],[5,1.0],[4,1.0],[1,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[1,1.0],[6,1.0],[2,1.0],[0,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[2,1.0],[7,1.0],[3,1.0],[1,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[3,1.0],[8,1.0],[4,1.0],[2,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[4,1.0],[9,1.0],[3,1.0],[0,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[5,1.0],[8,1.0],[7,1.0],[0,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[6,1.0],[9,1.0],[8,1.0],[1,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[7,1.0],[9,1.0],[5,1.0],[2,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[8,1.0],[6,1.0],[5,1.0],[3,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[9,1.0],[7,1.0],[6,1.0],[4,1.0]]}],"num_vars":10,"objective":[[0,1.0],[1,1.0],[2,1.0],[3,1.0],[4,1.0],[5,1.0],[6,1.0],[7,1.0],[8,1.0],[9,1.0]],"sense":"Minimize"}},"solutions":[{"source_config":[0,0,1,0,0,1,0,0,0,1],"target_config":[0,0,1,0,0,1,0,0,0,1]}]}, {"source":{"problem":"MinimumSetCovering","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[2,3,4],[4,5,6],[6,7,0],[1,3,5],[0,4,7]],"universe_size":8,"weights":[1,1,1,1,1,1]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Ge","rhs":1.0,"terms":[[0,1.0],[3,1.0],[5,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[0,1.0],[4,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[0,1.0],[1,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[1,1.0],[4,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[1,1.0],[2,1.0],[5,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[2,1.0],[4,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[2,1.0],[3,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[3,1.0],[5,1.0]]}],"num_vars":6,"objective":[[0,1.0],[1,1.0],[2,1.0],[3,1.0],[4,1.0],[5,1.0]],"sense":"Minimize"}},"solutions":[{"source_config":[0,1,0,1,1,0],"target_config":[0,1,0,1,1,0]}]}, - {"source":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[0,1,1,0,1,1,0,0,1,1],"target_config":[1,0,0,1,0,0,1,1,0,0]}]}, - {"source":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MinimumSetCovering","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"universe_size":15,"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[0,1,1,0,1,1,0,0,1,1],"target_config":[0,1,1,0,1,1,0,0,1,1]}]}, + {"source":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[0,1,0,1,1,1,1,1,0,0],"target_config":[1,0,1,0,0,0,0,0,1,1]}]}, + {"source":{"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1]}},"target":{"problem":"MinimumSetCovering","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[0,3,4],[3,5,6],[5,7,8],[1,7,9],[2,10,11],[4,12,13],[6,10,14],[8,11,12],[9,13,14]],"universe_size":15,"weights":[1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[0,1,0,1,1,1,1,1,0,0],"target_config":[0,1,0,1,1,1,1,1,0,0]}]}, {"source":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-2.0,1.0,0.0,0.0],[0.0,-3.0,2.0,0.0],[0.0,0.0,-1.0,-1.0],[0.0,0.0,0.0,-4.0]],"num_vars":4}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":0.0,"terms":[[4,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[4,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[4,1.0],[0,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[5,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[5,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[5,1.0],[1,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[6,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[6,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[6,1.0],[2,-1.0],[3,-1.0]]}],"num_vars":7,"objective":[[0,-2.0],[1,-3.0],[2,-1.0],[3,-4.0],[4,1.0],[5,2.0],[6,-1.0]],"sense":"Minimize"}},"solutions":[{"source_config":[1,1,1,1],"target_config":[1,1,1,1,1,1,1]}]}, {"source":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-1.0,2.0,0.0,0.0,-1.5,2.0,0.0,0.0,0.0,0.0],[0.0,-0.8,-1.5,0.0,0.0,0.0,2.0,0.0,0.0,0.0],[0.0,0.0,-0.6,-1.5,0.0,0.0,0.0,2.0,0.0,0.0],[0.0,0.0,0.0,-0.3999999999999999,-1.5,0.0,0.0,0.0,2.0,0.0],[0.0,0.0,0.0,0.0,-0.19999999999999996,0.0,0.0,0.0,0.0,-1.5],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,-1.5,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.20000000000000018,0.0,2.0,-1.5],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.40000000000000013,0.0,2.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.6000000000000001,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.8]],"num_vars":10}},"target":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"f64"},"instance":{"couplings":[0.5,-0.375,0.5,-0.375,0.5,-0.375,0.5,-0.375,0.5,-0.375,0.5,-0.375,0.5,-0.375,0.5],"fields":[0.125,0.22499999999999998,-0.55,-0.44999999999999996,-1.225,0.625,0.7250000000000001,1.7000000000000002,0.925,0.15000000000000002],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[1,0,1,1,1,0,1,0,0,1],"target_config":[1,0,1,1,1,0,1,0,0,1]}]}, {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,-2,3]},{"literals":[-1,2]},{"literals":[2,3]}],"num_vars":3}},"target":{"problem":"CircuitSAT","variant":{},"instance":{"circuit":{"assignments":[{"expr":{"op":{"Or":[{"op":{"Var":"x1"}},{"op":{"Not":{"op":{"Var":"x2"}}}},{"op":{"Var":"x3"}}]}},"outputs":["__clause_0"]},{"expr":{"op":{"Or":[{"op":{"Not":{"op":{"Var":"x1"}}}},{"op":{"Var":"x2"}}]}},"outputs":["__clause_1"]},{"expr":{"op":{"Or":[{"op":{"Var":"x2"}},{"op":{"Var":"x3"}}]}},"outputs":["__clause_2"]},{"expr":{"op":{"And":[{"op":{"Var":"__clause_0"}},{"op":{"Var":"__clause_1"}},{"op":{"Var":"__clause_2"}}]}},"outputs":["__out"]},{"expr":{"op":{"Const":true}},"outputs":["__out"]}]},"variables":["__clause_0","__clause_1","__clause_2","__out","x1","x2","x3"]}},"solutions":[{"source_config":[1,1,1],"target_config":[1,1,1,1,1,1,1]}]}, {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1]},{"literals":[-3]},{"literals":[5]}],"num_vars":5}},"target":{"problem":"KColoring","variant":{"graph":"SimpleGraph","k":"K3"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null],[3,2,null],[8,2,null],[3,8,null],[4,2,null],[9,2,null],[4,9,null],[5,2,null],[10,2,null],[5,10,null],[6,2,null],[11,2,null],[6,11,null],[7,2,null],[12,2,null],[7,12,null],[3,2,null],[3,1,null],[10,2,null],[10,1,null],[7,2,null],[7,1,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null,null,null,null]}},"num_colors":3}},"solutions":[{"source_config":[1,1,0,1,1],"target_config":[2,1,0,2,2,1,2,2,1,1,2,1,1]}]}, - {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1]},{"literals":[2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[1,-2,3,-5]},{"literals":[-1,2,-3,4,5]}],"num_vars":5}},"target":{"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,6,7]},{"literals":[1,6,-7]},{"literals":[1,-6,8]},{"literals":[1,-6,-8]},{"literals":[2,-3,9]},{"literals":[2,-3,-9]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[1,-2,10]},{"literals":[-10,3,-5]},{"literals":[-1,2,11]},{"literals":[-11,-3,12]},{"literals":[-12,4,5]}],"num_vars":12}},"solutions":[{"source_config":[1,1,1,0,1],"target_config":[1,1,1,0,1,0,0,0,0,1,1,1]}]}, + {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1]},{"literals":[2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[1,-2,3,-5]},{"literals":[-1,2,-3,4,5]}],"num_vars":5}},"target":{"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,6,7]},{"literals":[1,6,-7]},{"literals":[1,-6,8]},{"literals":[1,-6,-8]},{"literals":[2,-3,9]},{"literals":[2,-3,-9]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[1,-2,10]},{"literals":[-10,3,-5]},{"literals":[-1,2,11]},{"literals":[-11,-3,12]},{"literals":[-12,4,5]}],"num_vars":12}},"solutions":[{"source_config":[1,0,0,1,1],"target_config":[1,0,0,1,1,0,0,0,0,0,1,1]}]}, {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[-2,3,-5]},{"literals":[1,-3,5]},{"literals":[-1,-2,4]},{"literals":[3,-4,-5]}],"num_vars":5}},"target":{"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"One"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null],[3,4,null],[3,5,null],[4,5,null],[6,7,null],[6,8,null],[7,8,null],[9,10,null],[9,11,null],[10,11,null],[12,13,null],[12,14,null],[13,14,null],[15,16,null],[15,17,null],[16,17,null],[18,19,null],[18,20,null],[19,20,null],[0,3,null],[0,15,null],[1,9,null],[1,16,null],[2,4,null],[2,10,null],[2,18,null],[3,12,null],[4,13,null],[5,7,null],[5,19,null],[6,9,null],[6,16,null],[7,17,null],[8,11,null],[8,20,null],[10,13,null],[11,14,null],[12,15,null],[13,18,null],[14,20,null],[17,19,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,1,1,1,0],"target_config":[1,0,0,0,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0]}]}, {"source":{"problem":"Satisfiability","variant":{},"instance":{"clauses":[{"literals":[1,2,-3]},{"literals":[-1,3,4]},{"literals":[2,-4,5]},{"literals":[-2,3,-5]},{"literals":[1,-3,5]},{"literals":[-1,-2,4]},{"literals":[3,-4,-5]}],"num_vars":5}},"target":{"problem":"MinimumDominatingSet","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null],[3,4,null],[3,5,null],[4,5,null],[6,7,null],[6,8,null],[7,8,null],[9,10,null],[9,11,null],[10,11,null],[12,13,null],[12,14,null],[13,14,null],[0,15,null],[3,15,null],[7,15,null],[1,16,null],[6,16,null],[9,16,null],[3,17,null],[10,17,null],[12,17,null],[4,18,null],[6,18,null],[13,18,null],[0,19,null],[7,19,null],[12,19,null],[1,20,null],[4,20,null],[9,20,null],[6,21,null],[10,21,null],[13,21,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}},"weights":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]}},"solutions":[{"source_config":[1,0,1,1,1],"target_config":[1,0,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0]}]}, - {"source":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"f64"},"instance":{"couplings":[1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0],"fields":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-2.0,4.0,0.0,0.0,-4.0,4.0,0.0,0.0,0.0,0.0],[0.0,-2.0,-4.0,0.0,0.0,0.0,4.0,0.0,0.0,0.0],[0.0,0.0,2.0,-4.0,0.0,0.0,0.0,4.0,0.0,0.0],[0.0,0.0,0.0,2.0,-4.0,0.0,0.0,0.0,4.0,0.0],[0.0,0.0,0.0,0.0,6.0,0.0,0.0,0.0,0.0,-4.0],[0.0,0.0,0.0,0.0,0.0,-2.0,0.0,4.0,-4.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,-2.0,0.0,4.0,-4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,0.0,4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0]],"num_vars":10}},"solutions":[{"source_config":[1,0,1,1,1,0,1,0,0,1],"target_config":[1,0,1,1,1,0,1,0,0,1]}]}, - {"source":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1],"fields":[0,0,0,0,0,0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"MaxCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[1,0,1,1,1,0,1,0,0,1],"target_config":[1,0,1,1,1,0,1,0,0,1]}]}, - {"source":{"problem":"TravelingSalesman","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[10,15,20,35,25,30],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[0,3,null],[1,2,null],[1,3,null],[2,3,null]],"node_holes":[],"nodes":[null,null,null,null]}}}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[1,1.0],[2,1.0],[3,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[4,1.0],[5,1.0],[6,1.0],[7,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[8,1.0],[9,1.0],[10,1.0],[11,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[12,1.0],[13,1.0],[14,1.0],[15,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[4,1.0],[8,1.0],[12,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[1,1.0],[5,1.0],[9,1.0],[13,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[2,1.0],[6,1.0],[10,1.0],[14,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[3,1.0],[7,1.0],[11,1.0],[15,1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[16,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[16,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[16,1.0],[0,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[17,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[17,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[17,1.0],[4,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[18,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[18,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[18,1.0],[1,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[19,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[19,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[19,1.0],[5,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[20,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[20,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[20,1.0],[2,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[21,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[21,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[21,1.0],[6,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[22,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[22,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[22,1.0],[3,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[23,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[23,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[23,1.0],[7,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[24,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[24,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[24,1.0],[0,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[25,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[25,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[25,1.0],[8,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[26,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[26,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[26,1.0],[1,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[27,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[27,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[27,1.0],[9,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[28,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[28,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[28,1.0],[2,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[29,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[29,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[29,1.0],[10,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[30,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[30,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[30,1.0],[3,-1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[31,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[31,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[31,1.0],[11,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[32,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[32,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[32,1.0],[0,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[33,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[33,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[33,1.0],[12,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[34,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[34,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[34,1.0],[1,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[35,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[35,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[35,1.0],[13,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[36,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[36,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[36,1.0],[2,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[37,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[37,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[37,1.0],[14,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[38,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[38,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[38,1.0],[3,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[39,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[39,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[39,1.0],[15,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[40,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[40,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[40,1.0],[4,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[41,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[41,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[41,1.0],[8,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[42,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[42,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[42,1.0],[5,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[43,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[43,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[43,1.0],[9,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[44,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[44,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[44,1.0],[6,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[45,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[45,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[45,1.0],[10,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[46,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[46,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[46,1.0],[7,-1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[47,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[47,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[47,1.0],[11,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[48,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[48,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[48,1.0],[4,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[49,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[49,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[49,1.0],[12,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[50,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[50,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[50,1.0],[5,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[51,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[51,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[51,1.0],[13,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[52,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[52,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[52,1.0],[6,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[53,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[53,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[53,1.0],[14,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[54,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[54,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[54,1.0],[7,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[55,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[55,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[55,1.0],[15,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[56,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[56,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[56,1.0],[8,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[57,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[57,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[57,1.0],[12,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[58,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[58,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[58,1.0],[9,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[59,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[59,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[59,1.0],[13,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[60,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[60,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[60,1.0],[10,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[61,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[61,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[61,1.0],[14,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[62,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[62,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[62,1.0],[11,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[63,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[63,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[63,1.0],[15,-1.0],[8,-1.0]]}],"num_vars":64,"objective":[[16,10.0],[17,10.0],[18,10.0],[19,10.0],[20,10.0],[21,10.0],[22,10.0],[23,10.0],[24,15.0],[25,15.0],[26,15.0],[27,15.0],[28,15.0],[29,15.0],[30,15.0],[31,15.0],[32,20.0],[33,20.0],[34,20.0],[35,20.0],[36,20.0],[37,20.0],[38,20.0],[39,20.0],[40,35.0],[41,35.0],[42,35.0],[43,35.0],[44,35.0],[45,35.0],[46,35.0],[47,35.0],[48,25.0],[49,25.0],[50,25.0],[51,25.0],[52,25.0],[53,25.0],[54,25.0],[55,25.0],[56,30.0],[57,30.0],[58,30.0],[59,30.0],[60,30.0],[61,30.0],[62,30.0],[63,30.0]],"sense":"Minimize"}},"solutions":[{"source_config":[1,1,0,0,1,1],"target_config":[1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0]}]}, - {"source":{"problem":"TravelingSalesman","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,2,3],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null]],"node_holes":[],"nodes":[null,null,null]}}}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-14.0,14.0,14.0,14.0,1.0,1.0,14.0,2.0,2.0],[0.0,-14.0,14.0,1.0,14.0,1.0,2.0,14.0,2.0],[0.0,0.0,-14.0,1.0,1.0,14.0,2.0,2.0,14.0],[0.0,0.0,0.0,-14.0,14.0,14.0,14.0,3.0,3.0],[0.0,0.0,0.0,0.0,-14.0,14.0,3.0,14.0,3.0],[0.0,0.0,0.0,0.0,0.0,-14.0,3.0,3.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,-14.0,14.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-14.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-14.0]],"num_vars":9}},"solutions":[{"source_config":[1,1,1],"target_config":[0,0,1,1,0,0,0,1,0]}]} + {"source":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"f64"},"instance":{"couplings":[1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0],"fields":[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-2.0,4.0,0.0,0.0,-4.0,4.0,0.0,0.0,0.0,0.0],[0.0,-2.0,-4.0,0.0,0.0,0.0,4.0,0.0,0.0,0.0],[0.0,0.0,2.0,-4.0,0.0,0.0,0.0,4.0,0.0,0.0],[0.0,0.0,0.0,2.0,-4.0,0.0,0.0,0.0,4.0,0.0],[0.0,0.0,0.0,0.0,6.0,0.0,0.0,0.0,0.0,-4.0],[0.0,0.0,0.0,0.0,0.0,-2.0,0.0,4.0,-4.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,-2.0,0.0,4.0,-4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.0,0.0,4.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0]],"num_vars":10}},"solutions":[{"source_config":[0,1,1,0,0,1,0,0,1,0],"target_config":[0,1,1,0,0,1,0,0,1,0]}]}, + {"source":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1],"fields":[0,0,0,0,0,0,0,0,0,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"target":{"problem":"MaxCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1,-1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,4,null],[0,5,null],[1,2,null],[1,6,null],[2,3,null],[2,7,null],[3,4,null],[3,8,null],[4,9,null],[5,7,null],[5,8,null],[6,8,null],[6,9,null],[7,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[0,1,1,0,0,1,0,0,1,0],"target_config":[0,1,1,0,0,1,0,0,1,0]}]}, + {"source":{"problem":"TravelingSalesman","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[10,15,20,35,25,30],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[0,3,null],[1,2,null],[1,3,null],[2,3,null]],"node_holes":[],"nodes":[null,null,null,null]}}}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[1,1.0],[2,1.0],[3,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[4,1.0],[5,1.0],[6,1.0],[7,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[8,1.0],[9,1.0],[10,1.0],[11,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[12,1.0],[13,1.0],[14,1.0],[15,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[4,1.0],[8,1.0],[12,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[1,1.0],[5,1.0],[9,1.0],[13,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[2,1.0],[6,1.0],[10,1.0],[14,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[3,1.0],[7,1.0],[11,1.0],[15,1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[16,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[16,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[16,1.0],[0,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[17,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[17,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[17,1.0],[4,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[18,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[18,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[18,1.0],[1,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[19,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[19,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[19,1.0],[5,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[20,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[20,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[20,1.0],[2,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[21,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[21,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[21,1.0],[6,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[22,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[22,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[22,1.0],[3,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[23,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[23,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[23,1.0],[7,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[24,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[24,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[24,1.0],[0,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[25,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[25,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[25,1.0],[8,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[26,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[26,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[26,1.0],[1,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[27,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[27,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[27,1.0],[9,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[28,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[28,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[28,1.0],[2,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[29,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[29,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[29,1.0],[10,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[30,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[30,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[30,1.0],[3,-1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[31,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[31,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[31,1.0],[11,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[32,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[32,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[32,1.0],[0,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[33,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[33,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[33,1.0],[12,-1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[34,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[34,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[34,1.0],[1,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[35,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[35,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[35,1.0],[13,-1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[36,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[36,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[36,1.0],[2,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[37,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[37,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[37,1.0],[14,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[38,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[38,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[38,1.0],[3,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[39,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[39,1.0],[0,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[39,1.0],[15,-1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[40,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[40,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[40,1.0],[4,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[41,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[41,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[41,1.0],[8,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[42,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[42,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[42,1.0],[5,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[43,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[43,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[43,1.0],[9,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[44,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[44,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[44,1.0],[6,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[45,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[45,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[45,1.0],[10,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[46,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[46,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[46,1.0],[7,-1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[47,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[47,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[47,1.0],[11,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[48,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[48,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[48,1.0],[4,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[49,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[49,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[49,1.0],[12,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[50,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[50,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[50,1.0],[5,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[51,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[51,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[51,1.0],[13,-1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[52,1.0],[6,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[52,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[52,1.0],[6,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[53,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[53,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[53,1.0],[14,-1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[54,1.0],[7,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[54,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[54,1.0],[7,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[55,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[55,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[55,1.0],[15,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[56,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[56,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[56,1.0],[8,-1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[57,1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[57,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[57,1.0],[12,-1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[58,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[58,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[58,1.0],[9,-1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[59,1.0],[13,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[59,1.0],[10,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[59,1.0],[13,-1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[60,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[60,1.0],[15,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[60,1.0],[10,-1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[61,1.0],[14,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[61,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[61,1.0],[14,-1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[62,1.0],[11,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[62,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[62,1.0],[11,-1.0],[12,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[63,1.0],[15,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[63,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[63,1.0],[15,-1.0],[8,-1.0]]}],"num_vars":64,"objective":[[16,10.0],[17,10.0],[18,10.0],[19,10.0],[20,10.0],[21,10.0],[22,10.0],[23,10.0],[24,15.0],[25,15.0],[26,15.0],[27,15.0],[28,15.0],[29,15.0],[30,15.0],[31,15.0],[32,20.0],[33,20.0],[34,20.0],[35,20.0],[36,20.0],[37,20.0],[38,20.0],[39,20.0],[40,35.0],[41,35.0],[42,35.0],[43,35.0],[44,35.0],[45,35.0],[46,35.0],[47,35.0],[48,25.0],[49,25.0],[50,25.0],[51,25.0],[52,25.0],[53,25.0],[54,25.0],[55,25.0],[56,30.0],[57,30.0],[58,30.0],[59,30.0],[60,30.0],[61,30.0],[62,30.0],[63,30.0]],"sense":"Minimize"}},"solutions":[{"source_config":[1,1,0,0,1,1],"target_config":[0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0]}]}, + {"source":{"problem":"TravelingSalesman","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,2,3],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,2,null]],"node_holes":[],"nodes":[null,null,null]}}}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-14.0,14.0,14.0,14.0,1.0,1.0,14.0,2.0,2.0],[0.0,-14.0,14.0,1.0,14.0,1.0,2.0,14.0,2.0],[0.0,0.0,-14.0,1.0,1.0,14.0,2.0,2.0,14.0],[0.0,0.0,0.0,-14.0,14.0,14.0,14.0,3.0,3.0],[0.0,0.0,0.0,0.0,-14.0,14.0,3.0,14.0,3.0],[0.0,0.0,0.0,0.0,0.0,-14.0,3.0,3.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,-14.0,14.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-14.0,14.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-14.0]],"num_vars":9}},"solutions":[{"source_config":[1,1,1],"target_config":[0,0,1,0,1,0,1,0,0]}]} ] } From 994f4145173c00675854b165832de44bbb9fce23 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Tue, 17 Mar 2026 03:01:41 +0800 Subject: [PATCH 5/7] fix: harden sequencing model validation --- problemreductions-cli/src/commands/create.rs | 42 ++++++++- problemreductions-cli/tests/cli_tests.rs | 63 +++++++++++++ ...ing_to_minimize_maximum_cumulative_cost.rs | 70 ++++++++++---- .../misc/sequencing_within_intervals.rs | 93 ++++++++++++++----- ...ing_to_minimize_maximum_cumulative_cost.rs | 15 +++ .../misc/sequencing_within_intervals.rs | 26 ++++++ 6 files changed, 269 insertions(+), 40 deletions(-) diff --git a/problemreductions-cli/src/commands/create.rs b/problemreductions-cli/src/commands/create.rs index de8cae421..382199728 100644 --- a/problemreductions-cli/src/commands/create.rs +++ b/problemreductions-cli/src/commands/create.rs @@ -279,7 +279,6 @@ fn type_format_hint(type_name: &str, graph_type: Option<&str>) -> &'static str { "Vec>" => "semicolon-separated groups: \"0,1;2,3\"", "usize" => "integer", "u64" => "integer", - "Vec" => "comma-separated integers: 0,0,5", "i64" => "integer", "BigUint" => "nonnegative decimal integer", "Vec" => "comma-separated nonnegative decimal integers: 3,7,1,8", @@ -389,6 +388,41 @@ fn parse_nonnegative_usize_bound(bound: i64, problem_name: &str, usage: &str) -> .map_err(|_| anyhow::anyhow!("{problem_name} requires nonnegative --bound\n\n{usage}")) } +fn validate_sequencing_within_intervals_inputs( + release_times: &[u64], + deadlines: &[u64], + lengths: &[u64], + usage: &str, +) -> Result<()> { + if release_times.len() != deadlines.len() { + bail!("release_times and deadlines must have the same length\n\n{usage}"); + } + if release_times.len() != lengths.len() { + bail!("release_times and lengths must have the same length\n\n{usage}"); + } + + for (i, ((&release_time, &deadline), &length)) in release_times + .iter() + .zip(deadlines.iter()) + .zip(lengths.iter()) + .enumerate() + { + let end = release_time.checked_add(length).ok_or_else(|| { + anyhow::anyhow!("Task {i}: overflow computing r(i) + l(i)\n\n{usage}") + })?; + if end > deadline { + bail!( + "Task {i}: r({}) + l({}) > d({}), time window is empty\n\n{usage}", + release_time, + length, + deadline + ); + } + } + + Ok(()) +} + fn print_problem_help(canonical: &str, graph_type: Option<&str>) -> Result<()> { let is_geometry = matches!( graph_type, @@ -1284,6 +1318,12 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> { let release_times: Vec = util::parse_comma_list(rt_str)?; let deadlines: Vec = util::parse_comma_list(dl_str)?; let lengths: Vec = util::parse_comma_list(len_str)?; + validate_sequencing_within_intervals_inputs( + &release_times, + &deadlines, + &lengths, + usage, + )?; ( ser(SequencingWithinIntervals::new( release_times, diff --git a/problemreductions-cli/tests/cli_tests.rs b/problemreductions-cli/tests/cli_tests.rs index c752247f2..ef6f41cdd 100644 --- a/problemreductions-cli/tests/cli_tests.rs +++ b/problemreductions-cli/tests/cli_tests.rs @@ -4992,4 +4992,67 @@ fn test_create_sequencing_within_intervals_rejects_empty_window() { .output() .unwrap(); assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + !stderr.contains("panicked at"), + "expected graceful CLI error, got panic: {stderr}" + ); + assert!( + stderr.contains("time window is empty"), + "expected empty-window validation error, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_within_intervals_rejects_mismatched_lengths() { + let output = pred() + .args([ + "create", + "SequencingWithinIntervals", + "--release-times", + "0,1", + "--deadlines", + "2", + "--lengths", + "1,1", + ]) + .output() + .unwrap(); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + !stderr.contains("panicked at"), + "expected graceful CLI error, got panic: {stderr}" + ); + assert!( + stderr.contains("must have the same length"), + "expected length validation error, got: {stderr}" + ); +} + +#[test] +fn test_create_sequencing_within_intervals_rejects_overflow() { + let output = pred() + .args([ + "create", + "SequencingWithinIntervals", + "--release-times", + "18446744073709551615", + "--deadlines", + "18446744073709551615", + "--lengths", + "1", + ]) + .output() + .unwrap(); + assert!(!output.status.success()); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!( + !stderr.contains("panicked at"), + "expected graceful CLI error, got panic: {stderr}" + ); + assert!( + stderr.contains("overflow computing r(i) + l(i)"), + "expected overflow validation error, got: {stderr}" + ); } diff --git a/src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs b/src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs index a365209d0..9dfdb7629 100644 --- a/src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs +++ b/src/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs @@ -6,6 +6,7 @@ use crate::registry::{FieldInfo, ProblemSchemaEntry}; use crate::traits::{Problem, SatisfactionProblem}; +use serde::de::Error as _; use serde::{Deserialize, Serialize}; inventory::submit! { @@ -34,13 +35,20 @@ inventory::submit! { /// /// Configurations use Lehmer-code dimensions `[n, n-1, ..., 1]` to encode a /// permutation of the task indices. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize)] pub struct SequencingToMinimizeMaximumCumulativeCost { costs: Vec, precedences: Vec<(usize, usize)>, bound: i64, } +#[derive(Debug, Deserialize)] +struct SequencingToMinimizeMaximumCumulativeCostUnchecked { + costs: Vec, + precedences: Vec<(usize, usize)>, + bound: i64, +} + impl SequencingToMinimizeMaximumCumulativeCost { /// Create a new instance. /// @@ -48,21 +56,7 @@ impl SequencingToMinimizeMaximumCumulativeCost { /// /// Panics if any precedence endpoint is out of range. pub fn new(costs: Vec, precedences: Vec<(usize, usize)>, bound: i64) -> Self { - let num_tasks = costs.len(); - for &(pred, succ) in &precedences { - assert!( - pred < num_tasks, - "predecessor index {} out of range (num_tasks = {})", - pred, - num_tasks - ); - assert!( - succ < num_tasks, - "successor index {} out of range (num_tasks = {})", - succ, - num_tasks - ); - } + validate_precedences(&precedences, costs.len()); Self { costs, precedences, @@ -113,6 +107,50 @@ impl SequencingToMinimizeMaximumCumulativeCost { } } +impl<'de> Deserialize<'de> for SequencingToMinimizeMaximumCumulativeCost { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let unchecked = + SequencingToMinimizeMaximumCumulativeCostUnchecked::deserialize(deserializer)?; + if let Some(message) = + precedence_validation_error(&unchecked.precedences, unchecked.costs.len()) + { + return Err(D::Error::custom(message)); + } + Ok(Self { + costs: unchecked.costs, + precedences: unchecked.precedences, + bound: unchecked.bound, + }) + } +} + +fn validate_precedences(precedences: &[(usize, usize)], num_tasks: usize) { + if let Some(message) = precedence_validation_error(precedences, num_tasks) { + panic!("{message}"); + } +} + +fn precedence_validation_error(precedences: &[(usize, usize)], num_tasks: usize) -> Option { + for &(pred, succ) in precedences { + if pred >= num_tasks { + return Some(format!( + "predecessor index {} out of range (num_tasks = {})", + pred, num_tasks + )); + } + if succ >= num_tasks { + return Some(format!( + "successor index {} out of range (num_tasks = {})", + succ, num_tasks + )); + } + } + None +} + impl Problem for SequencingToMinimizeMaximumCumulativeCost { const NAME: &'static str = "SequencingToMinimizeMaximumCumulativeCost"; type Metric = bool; diff --git a/src/models/misc/sequencing_within_intervals.rs b/src/models/misc/sequencing_within_intervals.rs index cd7c3efe4..c6a89bac7 100644 --- a/src/models/misc/sequencing_within_intervals.rs +++ b/src/models/misc/sequencing_within_intervals.rs @@ -6,6 +6,7 @@ use crate::registry::{FieldInfo, ProblemSchemaEntry}; use crate::traits::{Problem, SatisfactionProblem}; +use serde::de::Error as _; use serde::{Deserialize, Serialize}; inventory::submit! { @@ -53,7 +54,7 @@ inventory::submit! { /// let solution = solver.find_satisfying(&problem); /// assert!(solution.is_some()); /// ``` -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize)] pub struct SequencingWithinIntervals { /// Release times for each task. release_times: Vec, @@ -63,6 +64,13 @@ pub struct SequencingWithinIntervals { lengths: Vec, } +#[derive(Debug, Deserialize)] +struct SequencingWithinIntervalsUnchecked { + release_times: Vec, + deadlines: Vec, + lengths: Vec, +} + impl SequencingWithinIntervals { /// Create a new SequencingWithinIntervals problem. /// @@ -70,28 +78,7 @@ impl SequencingWithinIntervals { /// Panics if the three vectors have different lengths, or if any task has /// `r(i) + l(i) > d(i)` (empty time window). pub fn new(release_times: Vec, deadlines: Vec, lengths: Vec) -> Self { - assert_eq!( - release_times.len(), - deadlines.len(), - "release_times and deadlines must have the same length" - ); - assert_eq!( - release_times.len(), - lengths.len(), - "release_times and lengths must have the same length" - ); - for i in 0..release_times.len() { - let sum = release_times[i] - .checked_add(lengths[i]) - .expect("overflow computing r(i) + l(i)"); - assert!( - sum <= deadlines[i], - "Task {i}: r({}) + l({}) > d({}), time window is empty", - release_times[i], - lengths[i], - deadlines[i] - ); - } + validate_time_windows(&release_times, &deadlines, &lengths); Self { release_times, deadlines, @@ -120,6 +107,66 @@ impl SequencingWithinIntervals { } } +impl<'de> Deserialize<'de> for SequencingWithinIntervals { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let unchecked = SequencingWithinIntervalsUnchecked::deserialize(deserializer)?; + if let Some(message) = time_window_validation_error( + &unchecked.release_times, + &unchecked.deadlines, + &unchecked.lengths, + ) { + return Err(D::Error::custom(message)); + } + Ok(Self { + release_times: unchecked.release_times, + deadlines: unchecked.deadlines, + lengths: unchecked.lengths, + }) + } +} + +fn validate_time_windows(release_times: &[u64], deadlines: &[u64], lengths: &[u64]) { + if let Some(message) = time_window_validation_error(release_times, deadlines, lengths) { + panic!("{message}"); + } +} + +fn time_window_validation_error( + release_times: &[u64], + deadlines: &[u64], + lengths: &[u64], +) -> Option { + if release_times.len() != deadlines.len() { + return Some("release_times and deadlines must have the same length".to_string()); + } + if release_times.len() != lengths.len() { + return Some("release_times and lengths must have the same length".to_string()); + } + + for (i, ((&release_time, &deadline), &length)) in release_times + .iter() + .zip(deadlines.iter()) + .zip(lengths.iter()) + .enumerate() + { + let end = match release_time.checked_add(length) { + Some(end) => end, + None => return Some(format!("Task {i}: overflow computing r(i) + l(i)")), + }; + if end > deadline { + return Some(format!( + "Task {i}: r({}) + l({}) > d({}), time window is empty", + release_time, length, deadline + )); + } + } + + None +} + impl Problem for SequencingWithinIntervals { const NAME: &'static str = "SequencingWithinIntervals"; type Metric = bool; diff --git a/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs b/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs index 9013da9cd..fa6a4823f 100644 --- a/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs +++ b/src/unit_tests/models/misc/sequencing_to_minimize_maximum_cumulative_cost.rs @@ -126,3 +126,18 @@ fn test_sequencing_to_minimize_maximum_cumulative_cost_serialization() { assert_eq!(restored.precedences(), problem.precedences()); assert_eq!(restored.bound(), problem.bound()); } + +#[test] +fn test_sequencing_to_minimize_maximum_cumulative_cost_deserialize_rejects_invalid_precedence() { + let result: Result = + serde_json::from_value(serde_json::json!({ + "costs": [1, -1, 2], + "precedences": [[4, 0]], + "bound": 2 + })); + let err = result.unwrap_err().to_string(); + assert!( + err.contains("predecessor index 4 out of range"), + "got: {err}" + ); +} diff --git a/src/unit_tests/models/misc/sequencing_within_intervals.rs b/src/unit_tests/models/misc/sequencing_within_intervals.rs index b3b5d3205..c54745aaa 100644 --- a/src/unit_tests/models/misc/sequencing_within_intervals.rs +++ b/src/unit_tests/models/misc/sequencing_within_intervals.rs @@ -153,3 +153,29 @@ fn test_sequencing_within_intervals_invalid_window() { // r + l > d: impossible task SequencingWithinIntervals::new(vec![5], vec![3], vec![2]); } + +#[test] +fn test_sequencing_within_intervals_deserialize_rejects_mismatched_lengths() { + let result: Result = serde_json::from_value(serde_json::json!({ + "release_times": [0, 1], + "deadlines": [2], + "lengths": [1, 1] + })); + let err = result.unwrap_err().to_string(); + assert!( + err.contains("release_times and deadlines must have the same length") + || err.contains("release_times and lengths must have the same length"), + "got: {err}" + ); +} + +#[test] +fn test_sequencing_within_intervals_deserialize_rejects_empty_window() { + let result: Result = serde_json::from_value(serde_json::json!({ + "release_times": [5], + "deadlines": [3], + "lengths": [2] + })); + let err = result.unwrap_err().to_string(); + assert!(err.contains("time window is empty"), "got: {err}"); +} From 3a072c649f1c7ef2dd1ca7c19fbb2da20de0cf1c Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Thu, 19 Mar 2026 23:56:19 +0800 Subject: [PATCH 6/7] fix: update paper Typst to use new example-db format after merge with main The paper's SequencingToMinimizeMaximumCumulativeCost section used the old x.samples / x.optimal format. Updated to x.optimal_config / x.optimal_value to match the current example-db JSON schema. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/paper/reductions.typ | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ index f184bd827..720b777a1 100644 --- a/docs/paper/reductions.typ +++ b/docs/paper/reductions.typ @@ -3505,9 +3505,7 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76], let precs = x.instance.precedences let bound = x.instance.bound let ntasks = costs.len() - let sample = x.samples.at(0) - let satisfying-count = x.optimal.len() - let lehmer = sample.config + let lehmer = x.optimal_config let schedule = { let avail = range(ntasks) let result = () @@ -3536,7 +3534,7 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76], When the precedence constraints form a series-parallel digraph, #cite(, form: "prose") gave a polynomial-time algorithm running in $O(n^2)$ time. #cite(, form: "prose") placed the problem in a broader family of sequencing objectives solvable efficiently on series-parallel precedence structures. The implementation here uses Lehmer-code enumeration of task orders, so the direct exact search induced by the model runs in $O(n!)$ time. - *Example.* Consider $n = #ntasks$ tasks with costs $(#costs.map(c => str(c)).join(", "))$, precedence constraints #{precs.map(p => [$t_#(p.at(0) + 1) prec.eq t_#(p.at(1) + 1)$]).join(", ")}, and bound $K = #bound$. The sample schedule $(#schedule.map(t => $t_#(t + 1)$).join(", "))$ has cumulative sums $(#prefix-sums.map(v => str(v)).join(", "))$, so every prefix stays at or below $K = #bound$. Our brute-force solver finds exactly #satisfying-count satisfying schedules for this instance. + *Example.* Consider $n = #ntasks$ tasks with costs $(#costs.map(c => str(c)).join(", "))$, precedence constraints #{precs.map(p => [$t_#(p.at(0) + 1) prec.eq t_#(p.at(1) + 1)$]).join(", ")}, and bound $K = #bound$. The sample schedule $(#schedule.map(t => $t_#(t + 1)$).join(", "))$ has cumulative sums $(#prefix-sums.map(v => str(v)).join(", "))$, so every prefix stays at or below $K = #bound$. #figure( { From d6302994417c28b19cd75d3afedc78631359f410 Mon Sep 17 00:00:00 2001 From: Xiwei Pan Date: Fri, 20 Mar 2026 00:07:43 +0800 Subject: [PATCH 7/7] revert: remove unrelated SequencingWithinIntervals changes from this PR Co-Authored-By: Claude Opus 4.6 (1M context) --- .../misc/sequencing_within_intervals.rs | 93 +++++-------------- .../misc/sequencing_within_intervals.rs | 26 ------ 2 files changed, 23 insertions(+), 96 deletions(-) diff --git a/src/models/misc/sequencing_within_intervals.rs b/src/models/misc/sequencing_within_intervals.rs index bfef0c869..ed42ef47c 100644 --- a/src/models/misc/sequencing_within_intervals.rs +++ b/src/models/misc/sequencing_within_intervals.rs @@ -6,7 +6,6 @@ use crate::registry::{FieldInfo, ProblemSchemaEntry}; use crate::traits::{Problem, SatisfactionProblem}; -use serde::de::Error as _; use serde::{Deserialize, Serialize}; inventory::submit! { @@ -54,7 +53,7 @@ inventory::submit! { /// let solution = solver.find_satisfying(&problem); /// assert!(solution.is_some()); /// ``` -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct SequencingWithinIntervals { /// Release times for each task. release_times: Vec, @@ -64,13 +63,6 @@ pub struct SequencingWithinIntervals { lengths: Vec, } -#[derive(Debug, Deserialize)] -struct SequencingWithinIntervalsUnchecked { - release_times: Vec, - deadlines: Vec, - lengths: Vec, -} - impl SequencingWithinIntervals { /// Create a new SequencingWithinIntervals problem. /// @@ -78,7 +70,28 @@ impl SequencingWithinIntervals { /// Panics if the three vectors have different lengths, or if any task has /// `r(i) + l(i) > d(i)` (empty time window). pub fn new(release_times: Vec, deadlines: Vec, lengths: Vec) -> Self { - validate_time_windows(&release_times, &deadlines, &lengths); + assert_eq!( + release_times.len(), + deadlines.len(), + "release_times and deadlines must have the same length" + ); + assert_eq!( + release_times.len(), + lengths.len(), + "release_times and lengths must have the same length" + ); + for i in 0..release_times.len() { + let sum = release_times[i] + .checked_add(lengths[i]) + .expect("overflow computing r(i) + l(i)"); + assert!( + sum <= deadlines[i], + "Task {i}: r({}) + l({}) > d({}), time window is empty", + release_times[i], + lengths[i], + deadlines[i] + ); + } Self { release_times, deadlines, @@ -107,66 +120,6 @@ impl SequencingWithinIntervals { } } -impl<'de> Deserialize<'de> for SequencingWithinIntervals { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let unchecked = SequencingWithinIntervalsUnchecked::deserialize(deserializer)?; - if let Some(message) = time_window_validation_error( - &unchecked.release_times, - &unchecked.deadlines, - &unchecked.lengths, - ) { - return Err(D::Error::custom(message)); - } - Ok(Self { - release_times: unchecked.release_times, - deadlines: unchecked.deadlines, - lengths: unchecked.lengths, - }) - } -} - -fn validate_time_windows(release_times: &[u64], deadlines: &[u64], lengths: &[u64]) { - if let Some(message) = time_window_validation_error(release_times, deadlines, lengths) { - panic!("{message}"); - } -} - -fn time_window_validation_error( - release_times: &[u64], - deadlines: &[u64], - lengths: &[u64], -) -> Option { - if release_times.len() != deadlines.len() { - return Some("release_times and deadlines must have the same length".to_string()); - } - if release_times.len() != lengths.len() { - return Some("release_times and lengths must have the same length".to_string()); - } - - for (i, ((&release_time, &deadline), &length)) in release_times - .iter() - .zip(deadlines.iter()) - .zip(lengths.iter()) - .enumerate() - { - let end = match release_time.checked_add(length) { - Some(end) => end, - None => return Some(format!("Task {i}: overflow computing r(i) + l(i)")), - }; - if end > deadline { - return Some(format!( - "Task {i}: r({}) + l({}) > d({}), time window is empty", - release_time, length, deadline - )); - } - } - - None -} - impl Problem for SequencingWithinIntervals { const NAME: &'static str = "SequencingWithinIntervals"; type Metric = bool; diff --git a/src/unit_tests/models/misc/sequencing_within_intervals.rs b/src/unit_tests/models/misc/sequencing_within_intervals.rs index 97252d580..cd4e3a534 100644 --- a/src/unit_tests/models/misc/sequencing_within_intervals.rs +++ b/src/unit_tests/models/misc/sequencing_within_intervals.rs @@ -181,29 +181,3 @@ fn test_sequencing_within_intervals_invalid_window() { // r + l > d: impossible task SequencingWithinIntervals::new(vec![5], vec![3], vec![2]); } - -#[test] -fn test_sequencing_within_intervals_deserialize_rejects_mismatched_lengths() { - let result: Result = serde_json::from_value(serde_json::json!({ - "release_times": [0, 1], - "deadlines": [2], - "lengths": [1, 1] - })); - let err = result.unwrap_err().to_string(); - assert!( - err.contains("release_times and deadlines must have the same length") - || err.contains("release_times and lengths must have the same length"), - "got: {err}" - ); -} - -#[test] -fn test_sequencing_within_intervals_deserialize_rejects_empty_window() { - let result: Result = serde_json::from_value(serde_json::json!({ - "release_times": [5], - "deadlines": [3], - "lengths": [2] - })); - let err = result.unwrap_err().to_string(); - assert!(err.contains("time window is empty"), "got: {err}"); -}