diff --git a/.claude/skills/final-review/SKILL.md b/.claude/skills/final-review/SKILL.md index 9e12a2c49..ffcf3cac6 100644 --- a/.claude/skills/final-review/SKILL.md +++ b/.claude/skills/final-review/SKILL.md @@ -150,12 +150,12 @@ Use `AskUserQuestion` with your recommendation: Scan the PR diff for dangerous actions: -- **Blacklisted files**: If the diff touches `docs/src/reductions/reduction_graph.json` or `docs/src/reductions/problem_schemas.json`, **block merge**. These files are auto-generated and must not be committed in PRs — they are rebuilt by CI/`make doc`. Flag immediately and recommend OnHold. +- **Blacklisted files**: If the diff touches `docs/src/reductions/reduction_graph.json`, `docs/src/reductions/problem_schemas.json`, or `src/example_db/fixtures/examples.json` (legacy, no longer exists), **block merge**. These files are auto-generated and must not be committed in PRs — they are rebuilt by CI/`make doc`/`make paper`. Flag immediately and recommend OnHold. - **Removed features**: Any existing model, rule, test, or example deleted? - **Unrelated changes**: Files modified that don't belong to this PR (e.g., changes to unrelated models/rules, CI config, Cargo.toml dependency changes not needed for this PR) - **Force push indicators**: Any sign of history rewriting - **Broad modifications**: Changes to core traits, macros, or shared infrastructure that could affect other features -- **`examples.json` one-line rule**: Each PR should add exactly one model or one rule entry to `examples.json`. Check the **PR diff** (`gh pr diff`), not the post-merge-with-main diff — after merging main, fixture regeneration may touch many lines from other PRs. Only flag if the PR's own changes add or modify more than one entry. +- **No committed `examples.json`**: The example database is generated on demand by `make paper` (via `export_examples`). PRs should not commit `src/example_db/fixtures/examples.json` (legacy path, deleted) or `docs/paper/data/examples.json` (current output path) — both are gitignored build artifacts. Report findings with fix options for each concern: @@ -217,10 +217,10 @@ Verify the PR includes all required components: **Paper-example consistency check (both Model and Rule PRs):** -The paper example must use data from the canonical fixture JSON (`src/example_db/fixtures/examples.json`), not hand-written data. To verify: -1. If the PR changes example builders/specs, run `make regenerate-fixtures` on the PR branch. +The paper example must use data from the canonical example database (generated on demand by `make paper` via `export_examples`), not hand-written data. To verify: +1. If the PR changes example specs, run `make paper` to regenerate `docs/paper/data/examples.json`. 2. For **[Rule] PRs**: the paper's `reduction-rule` entry must call `load-example(source, target, ...)` (defined in `reductions.typ`) to load the canonical example from `examples.json`, and derive all concrete values from the loaded data using Typst array operations — no hand-written instance data. -3. For **[Model] PRs**: read the problem's entry in `examples.json` under `models` and compare its `instance` field against the paper's `problem-def` example. The paper example must use the same instance (allowing 0-indexed JSON vs 1-indexed math notation). If they differ, flag: "Paper example does not match `example_db` canonical instance in `examples.json`." +3. For **[Model] PRs**: run the export and read the problem's entry in the generated `examples.json` under `models`, compare its `instance` field against the paper's `problem-def` example. The paper example must use the same instance (allowing 0-indexed JSON vs 1-indexed math notation). If they differ, flag: "Paper example does not match `example_db` canonical instance." **Issue–test round-trip consistency check (both Model and Rule PRs):** @@ -338,13 +338,32 @@ Use `AskUserQuestion`: ```bash gh pr review --approve || true ``` -5. Present the PR link for the reviewer to merge: - > CI green, commits pushed, PR approved. Please merge when ready: +5. Post a community call validation checklist as a comment on the **linked issue** (not the PR). All CLI commands must be copy-pastable — substitute actual problem names from the PR diff (no angle-bracket placeholders). Example for a rule PR adding `Satisfiability` → `MaximumIndependentSet`: + ````bash + COMMENT_FILE=$(mktemp) + cat > "$COMMENT_FILE" <<'EOF' + Please kindly check the following items (PR #123): + - [ ] **Paper** ([PDF](https://github.com/CodingThrust/problem-reductions/blob/main/docs/paper/reductions.pdf)): check definition, proof sketch, and example figure + - [ ] **CLI demo** (build from source: `cargo install --path problemreductions-cli`): + ```bash + pred show Satisfiability + pred create --example Satisfiability -o instance.json + pred reduce instance.json Satisfiability MaximumIndependentSet -o reduced.json + pred solve reduced.json MaximumIndependentSet + ``` + - [ ] **Implementation (Optional)**: spot-check the source files changed in this PR for correctness + EOF + gh issue comment --body-file "$COMMENT_FILE" + rm -f "$COMMENT_FILE" + ```` + For model PRs, omit the `pred reduce` / `pred solve` lines. If there is no linked issue, post the checklist as a PR comment instead. +6. Present the PR link for the reviewer to merge: + > CI green, commits pushed, PR approved. Community call checklist posted on #. Please merge when ready: > **** -6. After the reviewer merges, use `AskUserQuestion` to confirm: +7. After the reviewer merges, use `AskUserQuestion` to confirm: > **Merged? (continue to move card & cleanup worktree)** Once confirmed, I will move the board item to Done and clean up the worktree. > - "Yes" — proceed with cleanup -7. Move the project board item to `Done` and clean up: +8. Move the project board item to `Done` and clean up: ```bash python3 scripts/pipeline_board.py move done cd "$REPO_ROOT" diff --git a/.claude/skills/review-pipeline/SKILL.md b/.claude/skills/review-pipeline/SKILL.md index 55487b313..f8511f88f 100644 --- a/.claude/skills/review-pipeline/SKILL.md +++ b/.claude/skills/review-pipeline/SKILL.md @@ -125,11 +125,15 @@ The two expensive context calls are allowed exactly once each per top-level `rev Branch from the review-pipeline report: - `Bundle status: empty` => the selected PR is no longer eligible; run `cd "$REPO_ROOT" && python3 scripts/pipeline_worktree.py cleanup --worktree "$WORKTREE_DIR"`, then for untargeted runs return to Step 0a, for explicit `PR` runs STOP - `Bundle status: needs-user-choice` => run `cd "$REPO_ROOT" && python3 scripts/pipeline_worktree.py cleanup --worktree "$WORKTREE_DIR"`, STOP and ask the user which PR is intended -- `Bundle status: ready` => continue +- `Bundle status: ready` => claim the item and continue -The bundle already handled the mechanical claim step (moved to Under review). Use the identifiers from the report for all subsequent operations. +**Claim the item** (move to Under review) only after confirming `Bundle status: ready`: -All subsequent steps run inside the worktree and should read facts from the reports instead of re-fetching them. +```bash +python3 scripts/pipeline_board.py move under-review +``` + +Use the identifiers from the report for all subsequent operations. All subsequent steps run inside the worktree and should read facts from the reports instead of re-fetching them. ### 1. Run Three Sub-Reviews (Parallel) diff --git a/.github/ISSUE_TEMPLATE/problem.md b/.github/ISSUE_TEMPLATE/problem.md index eca24a63b..7611d1716 100644 --- a/.github/ISSUE_TEMPLATE/problem.md +++ b/.github/ISSUE_TEMPLATE/problem.md @@ -95,6 +95,9 @@ This example will be shown in our paper, where you could find some references. ## BibTeX diff --git a/.gitignore b/.gitignore index 2317aab1d..5ed72dbfb 100644 --- a/.gitignore +++ b/.gitignore @@ -78,13 +78,13 @@ pkgref/ # Generated example outputs docs/paper/examples/ +docs/paper/data/ # Claude Code logs claude-output.log .worktrees/ .worktree/ *.json -!src/example_db/fixtures/*.json .claude/worktrees/ docs/test-reports/ docs/superpowers/ diff --git a/Cargo.toml b/Cargo.toml index 45071c49c..9ee646cdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,8 +46,8 @@ name = "solver_benchmarks" harness = false [[example]] -name = "regenerate_fixtures" -path = "examples/regenerate_fixtures.rs" +name = "export_examples" +path = "examples/export_examples.rs" required-features = ["example-db"] [profile.release] diff --git a/Makefile b/Makefile index e238c1bd6..225d2c432 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Makefile for problemreductions -.PHONY: help build test mcp-test fmt clippy doc mdbook paper clean coverage rust-export compare qubo-testdata export-schemas release run-plan run-issue run-pipeline run-pipeline-forever run-review run-review-forever board-next board-claim board-ack board-move issue-context issue-guards pr-context pr-wait-ci worktree-issue worktree-pr diagrams jl-testdata cli cli-demo copilot-review regenerate-fixtures +.PHONY: help build test mcp-test fmt clippy doc mdbook paper clean coverage rust-export compare qubo-testdata export-schemas release run-plan run-issue run-pipeline run-pipeline-forever run-review run-review-forever board-next board-claim board-ack board-move issue-context issue-guards pr-context pr-wait-ci worktree-issue worktree-pr diagrams jl-testdata cli cli-demo copilot-review RUNNER ?= codex CLAUDE_MODEL ?= opus @@ -24,7 +24,6 @@ help: @echo " check - Quick check (fmt + clippy + test)" @echo " rust-export - Generate Rust mapping JSON exports" @echo " compare - Generate and compare Rust mapping exports" - @echo " regenerate-fixtures - Recompute example DB fixtures (BruteForce/ILP, slow)" @echo " export-schemas - Export problem schemas to JSON" @echo " qubo-testdata - Regenerate QUBO test data (requires uv)" @echo " jl-testdata - Regenerate Julia parity test data (requires julia)" @@ -113,16 +112,14 @@ mdbook: python3 -m http.server 3001 -d book & @sleep 1 && (command -v xdg-open >/dev/null && xdg-open http://localhost:3001 || open http://localhost:3001) -# Regenerate example DB fixtures from code (runs BruteForce/ILP — slow) -regenerate-fixtures: - cargo run --release --features "ilp-highs example-db" --example regenerate_fixtures # Export problem schemas to JSON export-schemas: cargo run --example export_schemas -# Build Typst paper (reads canonical examples directly from fixtures) +# Build Typst paper (generates example data on demand) paper: + cargo run --features "example-db" --example export_examples cargo run --example export_petersen_mapping cargo run --example export_graph cargo run --example export_schemas diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ index 8ea63dd0f..7da8fa082 100644 --- a/docs/paper/reductions.typ +++ b/docs/paper/reductions.typ @@ -16,7 +16,7 @@ // === Example JSON helpers === // Load canonical example database directly from the checked-in fixture file. -#let example-db = json("../../src/example_db/fixtures/examples.json") +#let example-db = json("data/examples.json") #let load-example(source, target, source-variant: none, target-variant: none) = { let matches = example-db.rules.filter(r => @@ -48,8 +48,8 @@ } } -#let graph-num-vertices(instance) = instance.graph.inner.nodes.len() -#let graph-num-edges(instance) = instance.graph.inner.edges.len() +#let graph-num-vertices(instance) = instance.graph.num_vertices +#let graph-num-edges(instance) = instance.graph.edges.len() #let spin-num-spins(instance) = instance.fields.len() #let sat-num-clauses(instance) = instance.clauses.len() #let subsetsum-num-elements(instance) = instance.sizes.len() @@ -416,8 +416,8 @@ In all graph problems below, $G = (V, E)$ denotes an undirected graph with $|V| let x = load-model-example("MaximumIndependentSet", variant: (graph: "SimpleGraph", weight: "One")) let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - // Pick optimal[2] = {v1, v3, v5, v9} to match figure - let sol = x.optimal.at(2) + // Pick optimal config = {v1, v3, v5, v9} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let S = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let alpha = sol.metric.Valid [ @@ -442,9 +442,9 @@ In all graph problems below, $G = (V, E)$ denotes an undirected graph with $|V| let x = load-model-example("MinimumVertexCover") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[2] = {v0, v3, v4} to match figure - let sol = x.optimal.at(2) + let edges = x.instance.graph.edges + // Pick optimal config = {v0, v3, v4} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let cover = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let wS = sol.metric.Valid let complement = sol.config.enumerate().filter(((i, v)) => v == 0).map(((i, _)) => i) @@ -474,9 +474,9 @@ In all graph problems below, $G = (V, E)$ denotes an undirected graph with $|V| let x = load-model-example("MaxCut") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[2] = S={v0, v3} to match figure - let sol = x.optimal.at(2) + let edges = x.instance.graph.edges + // Pick optimal config = S={v0, v3} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let side-s = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let side-sbar = sol.config.enumerate().filter(((i, v)) => v == 0).map(((i, _)) => i) let cut-val = sol.metric.Valid @@ -710,7 +710,7 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("LengthBoundedDisjointPaths") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let s = x.instance.source let t = x.instance.sink let J = x.instance.num_paths_required @@ -771,9 +771,9 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("HamiltonianPath") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[2] = [0, 2, 4, 3, 1, 5] to match figure - let sol = x.optimal.at(2) + let edges = x.instance.graph.edges + // Pick optimal config = [0, 2, 4, 3, 1, 5] to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let path = sol.config // Build path edges from consecutive vertices in the path let path-edges = range(path.len() - 1).map(i => (path.at(i), path.at(i + 1))) @@ -813,8 +813,7 @@ is feasible: each set induces a connected subgraph, the component weights are $2 } #{ let x = load-model-example("UndirectedTwoCommodityIntegralFlow") - let sample = x.samples.at(0) - let satisfying_count = x.optimal.len() + let satisfying_count = 1 let source1 = x.instance.source_1 let source2 = x.instance.source_2 let sink1 = x.instance.sink_1 @@ -826,7 +825,7 @@ is feasible: each set induces a connected subgraph, the component weights are $2 The implementation uses four variables per undirected edge ${u, v}$: $f_1(u, v)$, $f_1(v, u)$, $f_2(u, v)$, and $f_2(v, u)$. In the unit-capacity regime, each edge has exactly five meaningful local states: unused, commodity 1 in either direction, or commodity 2 in either direction, which matches the catalog bound $O(5^m)$ for $m = |E|$. - *Example.* Consider the graph with edges $(0, 2)$, $(1, 2)$, and $(2, 3)$, capacities $(1, 1, 2)$, sources $s_1 = v_#source1$, $s_2 = v_#source2$, and shared sink $t_1 = t_2 = v_#sink1$. The sample configuration in the fixture database sets $f_1(0, 2) = 1$, $f_2(1, 2) = 1$, and $f_1(2, 3) = f_2(2, 3) = 1$, with all reverse-direction variables zero. The only nonterminal vertex is $v_2$, where each commodity has one unit of inflow and one unit of outflow, so conservation holds. Vertex $v_3$ receives one unit of net inflow from each commodity, and the shared edge $(2,3)$ uses its full capacity 2. The fixture database contains exactly #satisfying_count satisfying configurations for this instance: the one shown below and the symmetric variant that swaps which commodity uses the two left edges. + *Example.* Consider the graph with edges $(0, 2)$, $(1, 2)$, and $(2, 3)$, capacities $(1, 1, 2)$, sources $s_1 = v_#source1$, $s_2 = v_#source2$, and shared sink $t_1 = t_2 = v_#sink1$. The optimal configuration in the fixture database sets $f_1(0, 2) = 1$, $f_2(1, 2) = 1$, and $f_1(2, 3) = f_2(2, 3) = 1$, with all reverse-direction variables zero. The only nonterminal vertex is $v_2$, where each commodity has one unit of inflow and one unit of outflow, so conservation holds. Vertex $v_3$ receives one unit of net inflow from each commodity, and the shared edge $(2,3)$ uses its full capacity 2. The fixture database contains #satisfying_count satisfying configuration for this instance, shown below. #figure( canvas(length: 1cm, { @@ -864,12 +863,12 @@ is feasible: each set induces a connected subgraph, the component weights are $2 } #{ let x = load-model-example("IsomorphicSpanningTree") - let g-edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - let t-edges = x.instance.tree.inner.edges.map(e => (e.at(0), e.at(1))) - let nv = x.instance.graph.inner.nodes.len() - let nt = x.instance.tree.inner.nodes.len() - // optimal[0] = identity mapping [0,1,2,3] - let sol = x.optimal.at(0) + let g-edges = x.instance.graph.edges + let t-edges = x.instance.tree.edges + let nv = x.instance.graph.num_vertices + let nt = x.instance.tree.num_vertices + // optimal config = identity mapping [0,1,2,3] + let sol = (config: x.optimal_config, metric: x.optimal_value) let pi = sol.config // Map tree edges through the bijection let mapped-edges = t-edges.map(((u, v)) => (pi.at(u), pi.at(v))) @@ -966,8 +965,8 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("KColoring") let nv = graph-num-vertices(x.instance) let k = x.instance.num_colors - // Pick optimal[0] = [0,1,1,0,2] to match figure - let sol = x.optimal.at(0) + // Pick optimal config = [0,1,1,0,2] to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let coloring = sol.config // Group vertices by color (1-indexed in display) let color-groups = range(k).map(c => coloring.enumerate().filter(((i, v)) => v == c).map(((i, _)) => i)) @@ -991,9 +990,9 @@ is feasible: each set induces a connected subgraph, the component weights are $2 #{ let x = load-model-example("MinimumDominatingSet") let nv = graph-num-vertices(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[0] = {v2, v3} to match figure - let sol = x.optimal.at(0) + let edges = x.instance.graph.edges + // Pick optimal config = {v2, v3} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let S = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let wS = sol.metric.Valid // Compute neighbors dominated by each vertex in S @@ -1026,9 +1025,9 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("MaximumMatching") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[4] = config [1,0,0,0,1,0] = edges {(0,1),(2,4)} to match figure - let sol = x.optimal.at(4) + let edges = x.instance.graph.edges + // Pick optimal config [1,0,0,0,1,0] = edges {(0,1),(2,4)} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let matched-edges = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => edges.at(i)) let wM = sol.metric.Valid // Collect matched vertices @@ -1059,9 +1058,9 @@ is feasible: each set induces a connected subgraph, the component weights are $2 #{ let x = load-model-example("TravelingSalesman") let nv = graph-num-vertices(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let ew = x.instance.edge_weights - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let tour-edges = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => edges.at(i)) let tour-cost = sol.metric.Valid // Build ordered tour from tour-edges starting at vertex 0 @@ -1121,10 +1120,10 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("SteinerTree") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let weights = x.instance.edge_weights let terminals = x.instance.terminals - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let tree-edge-indices = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let tree-edges = tree-edge-indices.map(i => edges.at(i)) let cost = sol.metric.Valid @@ -1185,12 +1184,12 @@ is feasible: each set induces a connected subgraph, the component weights are $2 } #{ let x = load-model-example("StrongConnectivityAugmentation") - let nv = x.instance.graph.inner.nodes.len() - let ne = x.instance.graph.inner.edges.len() - let arcs = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let nv = x.instance.graph.num_vertices + let ne = x.instance.graph.arcs.len() + let arcs = x.instance.graph.arcs let candidates = x.instance.candidate_arcs let bound = x.instance.bound - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let chosen = candidates.enumerate().filter(((i, _)) => sol.config.at(i) == 1).map(((i, arc)) => arc) let total-weight = chosen.map(a => a.at(2)).sum() let blue = graph-colors.at(0) @@ -1257,10 +1256,10 @@ is feasible: each set induces a connected subgraph, the component weights are $2 let x = load-model-example("MinimumMultiwayCut") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let weights = x.instance.edge_weights let terminals = x.instance.terminals - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let cut-edge-indices = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let cut-edges = cut-edge-indices.map(i => edges.at(i)) let cost = sol.metric.Valid @@ -1310,9 +1309,9 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let x = load-model-example("MaximumClique") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // optimal[0] = {v2, v3, v4} - let sol = x.optimal.at(0) + let edges = x.instance.graph.edges + // optimal config = {v2, v3, v4} + let sol = (config: x.optimal_config, metric: x.optimal_value) let K = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let omega = sol.metric.Valid // Edges within the clique @@ -1338,15 +1337,14 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let x = load-model-example("MaximalIS") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // optimal[0] = {v0,v2,v4} with w=3 (maximum-weight maximal IS) - let opt = x.optimal.at(0) + let edges = x.instance.graph.edges + // optimal config = {v0,v2,v4} with w=3 (maximum-weight maximal IS) + let opt = (config: x.optimal_config, metric: x.optimal_value) let S-opt = opt.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let w-opt = opt.metric.Valid - // samples[0] = {v1,v3} with w=2 (suboptimal maximal IS) - let sub = x.samples.at(0) - let S-sub = sub.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) - let w-sub = sub.metric.Valid + // Suboptimal maximal IS {v1,v3} with w=2 (hardcoded — no longer in fixture) + let S-sub = (1, 3) + let w-sub = 2 [ #problem-def("MaximalIS")[ Given $G = (V, E)$ with vertex weights $w: V -> RR$, find $S subset.eq V$ maximizing $sum_(v in S) w(v)$ such that $S$ is independent ($forall u, v in S: (u, v) in.not E$) and maximal (no vertex $u in V backslash S$ can be added to $S$ while maintaining independence). @@ -1367,10 +1365,10 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS #{ let x = load-model-example("MinimumFeedbackVertexSet") let nv = graph-num-vertices(x.instance) - let ne = graph-num-edges(x.instance) - let arcs = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - // Pick optimal[1] = {v0} to match figure - let sol = x.optimal.at(1) + let ne = x.instance.graph.arcs.len() + let arcs = x.instance.graph.arcs + // Pick optimal config = {v0} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let S = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let wS = sol.metric.Valid [ @@ -1406,11 +1404,11 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS #{ let x = load-model-example("MinimumSumMulticenter") let nv = graph-num-vertices(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let K = x.instance.k - let opt-cost = x.optimal.at(2).metric.Valid - // Pick optimal[2] = {v2, v5} to match figure - let sol = x.optimal.at(2) + let opt-cost = x.optimal_value.Valid + // Pick optimal config = {v2, v5} to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let centers = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) [ #problem-def("MinimumSumMulticenter")[ @@ -1456,8 +1454,8 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS // Compute universe size from all elements let all-elems = sets.flatten().dedup() let U-size = all-elems.len() - // Pick optimal[2] = {S1, S3} (0-indexed: sets 0, 2) to match figure - let sol = x.optimal.at(2) + // Pick optimal config = {S1, S3} (0-indexed: sets 0, 2) to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let selected = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let wP = sol.metric.Valid // Format a set as {e1+1, e2+1, ...} (1-indexed) @@ -1494,7 +1492,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let sets = x.instance.sets let m = sets.len() let U-size = x.instance.universe_size - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let selected = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) let wC = sol.metric.Valid let fmt-set(s) = "${" + s.map(e => str(e + 1)).join(", ") + "}$" @@ -1553,7 +1551,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let q = int(n / 3) let subs = x3c.instance.subsets let m = subs.len() - let sol = x3c.optimal.at(0).config + let sol = x3c.optimal_config // Format a 0-indexed triple as 1-indexed set notation: {a+1, b+1, c+1} let fmt-triple(t) = "${" + t.map(e => str(e + 1)).join(", ") + "}$" // Collect indices of selected subsets (1-indexed) @@ -1577,9 +1575,8 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let S = x.instance.s_sets let r-weights = x.instance.r_weights let s-weights = x.instance.s_weights - let sample = x.samples.at(0) - let selected = sample.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) - let satisfiers = x.optimal.map(sol => sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i)) + let selected = x.optimal_config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) + let satisfiers = ((config: x.optimal_config, metric: x.optimal_value),).map(sol => sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i)) let contains-selected(family-set) = selected.all(i => family-set.contains(i)) let r-active = range(R.len()).filter(i => contains-selected(R.at(i))) let s-active = range(S.len()).filter(i => contains-selected(S.at(i))) @@ -1640,10 +1637,9 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let m = coll.len() let U-size = x.instance.universe_size let k = x.instance.k - let sample = x.samples.at(0) - let sat-count = x.optimal.len() + let sat-count = 1 let basis = range(k).map(i => - range(U-size).filter(j => sample.config.at(i * U-size + j) == 1) + range(U-size).filter(j => x.optimal_config.at(i * U-size + j) == 1) ) let fmt-set(s) = "${" + s.map(e => str(e + 1)).join(", ") + "}$" [ @@ -1652,7 +1648,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS ][ The Set Basis problem was shown NP-complete by Stockmeyer @stockmeyer1975setbasis and appears as SP7 in Garey & Johnson @garey1979. It asks for an exact union-based description of a family of sets, unlike Set Cover which only requires covering the underlying universe. Applications include data compression, database schema design, and Boolean function minimization. The library's decision encoding uses $k |S|$ membership bits, so brute-force over those bits gives an $O^*(2^(k |S|))$ exact algorithm#footnote[This is the direct search bound induced by the encoding implemented here; we are not aware of a faster general exact worst-case algorithm for this representation.]. - *Example.* Let $S = {1, 2, 3, 4}$, $k = #k$, and $cal(C) = {#range(m).map(i => $C_#(i + 1)$).join(", ")}$ with #coll.enumerate().map(((i, s)) => $C_#(i + 1) = #fmt-set(s)$).join(", "). The sample basis from the issue is $cal(B) = {#range(k).map(i => $B_#(i + 1)$).join(", ")}$ with #basis.enumerate().map(((i, s)) => $B_#(i + 1) = #fmt-set(s)$).join(", "). Then $C_1 = B_1 union B_2$, $C_2 = B_2 union B_3$, $C_3 = B_1 union B_3$, and $C_4 = B_1 union B_2 union B_3$. There are #sat-count satisfying encodings in total: the singleton basis can be permuted in $3! = 6$ ways, and the three pair sets $C_1, C_2, C_3$ also form a basis with another six row permutations. + *Example.* Let $S = {1, 2, 3, 4}$, $k = #k$, and $cal(C) = {#range(m).map(i => $C_#(i + 1)$).join(", ")}$ with #coll.enumerate().map(((i, s)) => $C_#(i + 1) = #fmt-set(s)$).join(", "). The sample basis from the issue is $cal(B) = {#range(k).map(i => $B_#(i + 1)$).join(", ")}$ with #basis.enumerate().map(((i, s)) => $B_#(i + 1) = #fmt-set(s)$).join(", "). Then $C_1 = B_1 union B_2$, $C_2 = B_2 union B_3$, $C_3 = B_1 union B_3$, and $C_4 = B_1 union B_2 union B_3$. The fixture stores one satisfying encoding; other valid encodings exist (e.g., permuting the singleton basis or using the three pair sets $C_1, C_2, C_3$ as a basis). #figure( canvas(length: 1cm, { @@ -1699,10 +1695,10 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS #{ let x = load-model-example("SpinGlass") let n = spin-num-spins(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let ne = edges.len() - // Pick optimal[1] = (+,-,+,+,-) to match figure - let sol = x.optimal.at(1) + // Pick optimal config = (+,-,+,+,-) to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) // Convert config (0=+1, 1=-1) to spin values let spins = sol.config.map(v => if v == 0 { 1 } else { -1 }) let H = sol.metric.Valid @@ -1744,7 +1740,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let x = load-model-example("QUBO") let n = x.instance.num_vars let Q = x.instance.matrix - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let xstar = sol.config let fstar = sol.metric.Valid // Format the Q matrix as semicolon-separated rows @@ -1778,7 +1774,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let nv = x.instance.num_vars let obj = x.instance.objective let constraints = x.instance.constraints - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let xstar = sol.config let fstar = sol.metric.Valid // Format objective: c1*x1 + c2*x2 + ... @@ -1860,7 +1856,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let basis = x.instance.basis let target = x.instance.target let bounds = x.instance.bounds - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let dist = sol.metric.Valid // Config encodes offset from lower bound; recover actual integer coordinates let coords = sol.config.enumerate().map(((i, v)) => v + bounds.at(i).lower) @@ -1918,7 +1914,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let n = x.instance.num_vars let m = x.instance.clauses.len() let clauses = x.instance.clauses - let sol = x.optimal.at(1) // pick (1,0,1) + let sol = (config: x.optimal_config, metric: x.optimal_value) // pick satisfying assignment let assign = sol.config // Format a literal: positive l -> x_l, negative l -> not x_{|l|} let fmt-lit(l) = if l > 0 { $x_#l$ } else { $not x_#(-l)$ } @@ -1944,7 +1940,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let k = x.instance.clauses.at(0).literals.len() let clauses = x.instance.clauses // Pick a satisfying assignment - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let assign = sol.config let fmt-lit(l) = if l > 0 { $x_#l$ } else { $not x_#(-l)$ } let fmt-clause(c) = $paren.l #c.literals.map(fmt-lit).join($or$) paren.r$ @@ -1973,7 +1969,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let input-indices = inputs.map(v => vars.position(u => u == v)) // Collect unique input assignments from optimal configs let sat-assigns = () - for o in x.optimal { + for o in ((config: x.optimal_config, metric: x.optimal_value),) { let ia = input-indices.map(i => o.config.at(i)) if ia not in sat-assigns { sat-assigns.push(ia) } } @@ -2014,7 +2010,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let N = x.instance.target let mb = x.instance.m let nb = x.instance.n - let sol = x.optimal.at(0).config + let sol = x.optimal_config // First mb bits encode p, next nb bits encode q let p = range(mb).fold(0, (acc, i) => acc + sol.at(i) * calc.pow(2, i)) + 2 let q = range(nb).fold(0, (acc, i) => acc + sol.at(mb + i) * calc.pow(2, i)) + 2 @@ -2037,10 +2033,10 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let nc = x.instance.n let k = x.instance.k let A = x.instance.matrix - let dH = x.optimal.at(0).metric.Valid + let dH = x.optimal_value.Valid // Decode B and C from optimal config // Config layout: B is m*k values, then C is k*n values - let cfg = x.optimal.at(0).config + let cfg = x.optimal_config let B = range(mr).map(i => range(k).map(j => cfg.at(i * k + j))) let C = range(k).map(i => range(nc).map(j => cfg.at(mr * k + i * nc + j))) // Convert A from bool to int for display @@ -2089,7 +2085,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let labels = x.instance.car_labels let seq-indices = x.instance.sequence_indices let is-first = x.instance.is_first - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let assign = sol.config // color assignment per car let num-changes = sol.metric.Valid // Build the full sequence of car labels @@ -2138,7 +2134,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let k = x.instance.k let bip-edges = x.instance.graph.edges // (li, rj) pairs let ne = bip-edges.len() - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let total-size = sol.metric.Valid [ #problem-def("BicliqueCover")[ @@ -2177,7 +2173,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let right-size = x.instance.graph.right_size let k = x.instance.k let bip-edges = x.instance.graph.edges - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let left-selected = range(left-size).filter(i => sol.config.at(i) == 1) let right-selected = range(right-size).filter(i => sol.config.at(left-size + i) == 1) let selected-edges = bip-edges.filter(e => @@ -2241,10 +2237,10 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let x = load-model-example("PartitionIntoTriangles") let nv = graph-num-vertices(x.instance) let ne = graph-num-edges(x.instance) - let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) + let edges = x.instance.graph.edges let q = int(nv / 3) - // optimal[0] config groups vertices into triangles: config[i] = triangle index - let sol = x.optimal.at(0) + // optimal config groups vertices into triangles: config[i] = triangle index + let sol = (config: x.optimal_config, metric: x.optimal_value) let tri-assign = sol.config // Group vertices by triangle let triangles = range(q).map(t => tri-assign.enumerate().filter(((i, v)) => v == t).map(((i, _)) => i)) @@ -2464,8 +2460,8 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS // Alphabet mapping: 0->a, 1->b, 2->c, ... let alpha-map = range(alpha-size).map(i => str.from-unicode(97 + i)) let fmt-str(s) = "\"" + s.map(c => alpha-map.at(c)).join("") + "\"" - // Pick optimal[1] = [1,0,1,2] = "babc" to match figure - let sol = x.optimal.at(1) + // Pick optimal config = [1,0,1,2] = "babc" to match figure + let sol = (config: x.optimal_config, metric: x.optimal_value) let w = sol.config.map(c => alpha-map.at(c)) let w-str = fmt-str(sol.config) let w-len = w.len() @@ -2611,9 +2607,8 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS #{ let x = load-model-example("MultipleChoiceBranching") let nv = graph-num-vertices(x.instance) - let arcs = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1))) - let sol = x.samples.at(0) - let chosen = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) + let arcs = x.instance.graph.arcs + let chosen = x.optimal_config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i) [ #problem-def("MultipleChoiceBranching")[ Given a directed graph $G = (V, A)$, arc weights $w: A -> ZZ^+$, a partition $A_1, A_2, dots, A_m$ of $A$, and a threshold $K in ZZ^+$, determine whether there exists a subset $A' subset.eq A$ with $sum_(a in A') w(a) >= K$ such that every vertex has in-degree at most one in $(V, A')$, the selected subgraph $(V, A')$ is acyclic, and $|A' inter A_i| <= 1$ for every partition group. @@ -2622,7 +2617,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS A conservative exact algorithm enumerates all $2^{|A|}$ arc subsets and checks the partition, in-degree, acyclicity, and threshold constraints in polynomial time. This is the brute-force search space used by the implementation.#footnote[We use the registry complexity bound $O^*(2^{|A|})$ for the full partitioned problem.] - *Example.* Consider the digraph on $n = #nv$ vertices with arcs $(0 arrow 1), (0 arrow 2), (1 arrow 3), (2 arrow 3), (1 arrow 4), (3 arrow 5), (4 arrow 5), (2 arrow 4)$, partition groups $A_1 = {(0 arrow 1), (0 arrow 2)}$, $A_2 = {(1 arrow 3), (2 arrow 3)}$, $A_3 = {(1 arrow 4), (2 arrow 4)}$, $A_4 = {(3 arrow 5), (4 arrow 5)}$, and threshold $K = 10$. The highlighted selection $A' = {(0 arrow 1), (1 arrow 3), (2 arrow 4), (3 arrow 5)}$ has total weight $3 + 4 + 3 + 3 = 13 >= 10$, uses exactly one arc from each partition group, and gives in-degrees 1 at vertices $1, 3, 4,$ and $5$. Because every selected arc points strictly left-to-right in the drawing, the selected subgraph is acyclic. The canonical fixture contains #x.optimal.len() satisfying selections for this instance; the figure highlights one of them. + *Example.* Consider the digraph on $n = #nv$ vertices with arcs $(0 arrow 1), (0 arrow 2), (1 arrow 3), (2 arrow 3), (1 arrow 4), (3 arrow 5), (4 arrow 5), (2 arrow 4)$, partition groups $A_1 = {(0 arrow 1), (0 arrow 2)}$, $A_2 = {(1 arrow 3), (2 arrow 3)}$, $A_3 = {(1 arrow 4), (2 arrow 4)}$, $A_4 = {(3 arrow 5), (4 arrow 5)}$, and threshold $K = 10$. The highlighted selection $A' = {(0 arrow 1), (1 arrow 3), (2 arrow 4), (3 arrow 5)}$ has total weight $3 + 4 + 3 + 3 = 13 >= 10$, uses exactly one arc from each partition group, and gives in-degrees 1 at vertices $1, 3, 4,$ and $5$. Because every selected arc points strictly left-to-right in the drawing, the selected subgraph is acyclic. The figure highlights one satisfying selection for this instance. #figure({ let verts = ((0, 1.6), (1.3, 2.3), (1.3, 0.9), (3.0, 2.3), (3.0, 0.9), (4.6, 1.6)) @@ -2752,7 +2747,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let lengths = x.instance.lengths let num-processors = x.instance.num_processors let deadline = x.instance.deadline - let assignment = x.optimal.at(0).config + let assignment = x.optimal_config let tasks-by-processor = range(num-processors).map(p => range(lengths.len()).filter(i => assignment.at(i) == p) ) @@ -2822,7 +2817,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let release = x.instance.release_times let deadline = x.instance.deadlines let lengths = x.instance.lengths - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) // Compute start times from config offsets: start_i = release_i + config_i let starts = range(ntasks).map(i => release.at(i) + sol.config.at(i)) // Identify the enforcer task: the one with the tightest window (deadline - release == length) @@ -2915,7 +2910,7 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS let ntasks = x.instance.num_tasks let deadlines = x.instance.deadlines let precs = x.instance.precedences - let sol = x.optimal.at(0) + let sol = (config: x.optimal_config, metric: x.optimal_value) let tardy-count = sol.metric.Valid // Decode Lehmer code to permutation (schedule order) let lehmer = sol.config @@ -3605,7 +3600,7 @@ where $P$ is a penalty weight large enough that any constraint violation costs m #let mc_sg = load-example("MaxCut", "SpinGlass") #let mc_sg_sol = mc_sg.solutions.at(0) -#let mc_sg_cut = mc_sg.source.instance.graph.inner.edges.filter(e => mc_sg_sol.source_config.at(e.at(0)) != mc_sg_sol.source_config.at(e.at(1))).len() +#let mc_sg_cut = mc_sg.source.instance.graph.edges.filter(e => mc_sg_sol.source_config.at(e.at(0)) != mc_sg_sol.source_config.at(e.at(1))).len() #reduction-rule("MaxCut", "SpinGlass", example: true, example-caption: [Petersen graph ($n = 10$, unit weights) to Ising], diff --git a/examples/export_examples.rs b/examples/export_examples.rs new file mode 100644 index 000000000..b66d4feac --- /dev/null +++ b/examples/export_examples.rs @@ -0,0 +1,24 @@ +/// Export the example database as JSON for the Typst paper. +/// +/// Writes to `docs/paper/data/examples.json` (gitignored build artifact). +/// +/// ``` +/// cargo run --features "example-db" --example export_examples +/// ``` +use problemreductions::example_db::build_example_db; +use problemreductions::export::write_example_db_to; +use std::path::Path; + +fn main() { + let data_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("docs/paper/data"); + std::fs::create_dir_all(&data_dir).expect("Failed to create data directory"); + + let db = build_example_db().expect("Failed to build example database"); + write_example_db_to(&data_dir, &db); + + println!( + "Exported {} models, {} rules", + db.models.len(), + db.rules.len() + ); +} diff --git a/examples/regenerate_fixtures.rs b/examples/regenerate_fixtures.rs deleted file mode 100644 index 11d34670d..000000000 --- a/examples/regenerate_fixtures.rs +++ /dev/null @@ -1,31 +0,0 @@ -/// Regenerate example database fixture files from builder code. -/// -/// This binary recomputes all model and rule examples using BruteForce/ILP -/// and writes them to `src/example_db/fixtures/` as wrapped JSON objects. Run -/// this in release mode after changing any model or rule to update the stored -/// expected results: -/// -/// ``` -/// cargo run --release --example regenerate_fixtures --features "ilp-highs example-db" -/// ``` -use problemreductions::example_db::compute_example_db; -use problemreductions::export::write_example_db_to; -use std::fs; -use std::path::Path; - -fn main() { - let fixtures_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("src/example_db/fixtures"); - fs::create_dir_all(&fixtures_dir).expect("Failed to create fixtures directory"); - - let example_db = compute_example_db().expect("Failed to compute canonical example database"); - let examples_path = fixtures_dir.join("examples.json"); - - write_example_db_to(&fixtures_dir, &example_db); - - println!( - "Regenerated fixtures: {} rule examples, {} model examples", - example_db.rules.len(), - example_db.models.len() - ); - println!(" Examples: {}", examples_path.display()); -} diff --git a/problemreductions-cli/src/dispatch.rs b/problemreductions-cli/src/dispatch.rs index 5d63a9f77..53774c0f3 100644 --- a/problemreductions-cli/src/dispatch.rs +++ b/problemreductions-cli/src/dispatch.rs @@ -1,9 +1,7 @@ use anyhow::{Context, Result}; -use problemreductions::models::algebraic::ILP; use problemreductions::registry::{DynProblem, LoadedDynProblem}; use problemreductions::rules::{MinimizeSteps, ReductionGraph}; use problemreductions::solvers::ILPSolver; -use problemreductions::traits::Problem; use problemreductions::types::ProblemSize; use serde_json::Value; use std::any::Any; @@ -49,62 +47,36 @@ impl LoadedProblem { pub fn supports_ilp_solver(&self) -> bool { let name = self.problem_name(); - name == "ILP" || self.best_ilp_reduction_path().is_some() + let variant = self.variant_map(); + name == "ILP" || { + let graph = ReductionGraph::new(); + let ilp_variants = graph.variants_for("ILP"); + let input_size = ProblemSize::new(vec![]); + ilp_variants.iter().any(|dv| { + graph + .find_cheapest_path(name, &variant, "ILP", dv, &input_size, &MinimizeSteps) + .is_some() + }) + } } /// Solve using the ILP solver. If the problem is not ILP, auto-reduce to ILP first. pub fn solve_with_ilp(&self) -> Result { let name = self.problem_name(); - if name == "ILP" { - return solve_ilp(self.as_any()); - } - - let reduction_path = self.best_ilp_reduction_path().ok_or_else(|| { - anyhow::anyhow!( - "No reduction path from {} to ILP. Try `--solver brute-force`, or reduce to a problem that supports ILP.", - name - ) - })?; - let graph = ReductionGraph::new(); - - let chain = graph - .reduce_along_path(&reduction_path, self.as_any()) - .ok_or_else(|| anyhow::anyhow!("Failed to execute reduction chain to ILP"))?; - - let ilp_result = solve_ilp(chain.target_problem_any())?; - let config = chain.extract_solution(&ilp_result.config); + let variant = self.variant_map(); + let solver = ILPSolver::new(); + let config = solver + .solve_via_reduction(name, &variant, self.as_any()) + .ok_or_else(|| { + anyhow::anyhow!( + "No reduction path from {} to ILP or ILP solver found no solution. \ + Try `--solver brute-force`.", + name + ) + })?; let evaluation = self.evaluate_dyn(&config); Ok(SolveResult { config, evaluation }) } - - fn best_ilp_reduction_path(&self) -> Option { - let name = self.problem_name(); - let source_variant = self.variant_map(); - let graph = ReductionGraph::new(); - let ilp_variants = graph.variants_for("ILP"); - let input_size = ProblemSize::new(vec![]); - - let mut best_path = None; - for dv in &ilp_variants { - if let Some(path) = graph.find_cheapest_path( - name, - &source_variant, - "ILP", - dv, - &input_size, - &MinimizeSteps, - ) { - let is_better = best_path.as_ref().is_none_or( - |current: &problemreductions::rules::ReductionPath| path.len() < current.len(), - ); - if is_better { - best_path = Some(path); - } - } - } - - best_path - } } /// Load a problem from JSON type/variant/data. @@ -175,29 +147,6 @@ pub struct SolveResult { pub evaluation: String, } -/// Solve an ILP problem directly. The input must be an `ILP` or `ILP` instance. -fn solve_ilp(any: &dyn Any) -> Result { - if let Some(problem) = any.downcast_ref::>() { - let solver = ILPSolver::new(); - let config = solver - .solve(problem) - .ok_or_else(|| anyhow::anyhow!("ILP solver found no feasible solution"))?; - let evaluation = format!("{:?}", problem.evaluate(&config)); - return Ok(SolveResult { config, evaluation }); - } - if let Some(problem) = any.downcast_ref::>() { - let solver = ILPSolver::new(); - let config = solver - .solve(problem) - .ok_or_else(|| anyhow::anyhow!("ILP solver found no feasible solution"))?; - let evaluation = format!("{:?}", problem.evaluate(&config)); - return Ok(SolveResult { config, evaluation }); - } - Err(anyhow::anyhow!( - "Internal error: expected ILP or ILP problem instance" - )) -} - #[cfg(test)] mod tests { use super::*; @@ -234,12 +183,8 @@ mod tests { let variant = BTreeMap::from([("weight".to_string(), "i32".to_string())]); let data = json!({ "graph": { - "inner": { - "edge_property": "directed", - "nodes": [null, null, null], - "node_holes": [], - "edges": [[0, 1, null], [1, 2, null]] - } + "num_vertices": 3, + "arcs": [[0, 1], [1, 2]] }, "candidate_arcs": [[0, 3, 1]], "bound": 1 diff --git a/problemreductions-cli/tests/cli_tests.rs b/problemreductions-cli/tests/cli_tests.rs index e6ff49245..80acf4f0f 100644 --- a/problemreductions-cli/tests/cli_tests.rs +++ b/problemreductions-cli/tests/cli_tests.rs @@ -340,7 +340,7 @@ fn test_evaluate() { "type": "MaximumIndependentSet", "variant": {"graph": "SimpleGraph", "weight": "i32"}, "data": { - "graph": {"inner": {"nodes": [null, null, null, null], "node_holes": [], "edge_property": "undirected", "edges": [[0,1,null],[1,2,null],[2,3,null]]}}, + "graph": {"num_vertices": 4, "edges": [[0,1],[1,2],[2,3]]}, "weights": [1, 1, 1, 1] } }"#; @@ -387,7 +387,7 @@ fn test_evaluate_multiple_choice_branching_rejects_invalid_partition_without_pan "type": "MultipleChoiceBranching", "variant": {"weight": "i32"}, "data": { - "graph": {"inner": {"nodes": [null, null], "node_holes": [], "edge_property": "directed", "edges": [[0,1,null]]}}, + "graph": {"num_vertices": 2, "arcs": [[0,1]]}, "weights": [1], "partition": [[1]], "threshold": 1 @@ -620,7 +620,7 @@ fn test_reduce() { "type": "MIS", "variant": {"graph": "SimpleGraph", "weight": "i32"}, "data": { - "graph": {"inner": {"nodes": [null, null, null, null], "node_holes": [], "edge_property": "undirected", "edges": [[0,1,null],[1,2,null],[2,3,null]]}}, + "graph": {"num_vertices": 4, "edges": [[0,1],[1,2],[2,3]]}, "weights": [1, 1, 1, 1] } }"#; diff --git a/scripts/pipeline_skill_context.py b/scripts/pipeline_skill_context.py index f1219e65c..c3bfd6da6 100644 --- a/scripts/pipeline_skill_context.py +++ b/scripts/pipeline_skill_context.py @@ -608,8 +608,6 @@ def build_ambiguous_selection(candidate: dict, *, pr_number: int) -> dict: "pr_number": pr_number, "status": candidate.get("status"), "title": candidate.get("title"), - "claimed": True, - "claimed_status": pipeline_board.STATUS_UNDER_REVIEW, } @@ -1056,10 +1054,9 @@ def _select_candidate( return eligible[0] if eligible else None -def _selection_from_candidate(candidate: dict, *, mover: Callable[[str, str], None]) -> dict: - """Move the candidate to Under review and return a selection dict.""" +def _selection_from_candidate(candidate: dict) -> dict: + """Build a selection dict from a candidate (read-only, no board move).""" item_id = str(candidate["item_id"]) - mover(item_id, pipeline_board.STATUS_UNDER_REVIEW) return { "item_id": item_id, "number": int(candidate.get("pr_number") or candidate["number"]), @@ -1067,8 +1064,6 @@ def _selection_from_candidate(candidate: dict, *, mover: Callable[[str, str], No "pr_number": int(candidate.get("pr_number") or candidate["number"]), "status": candidate.get("status"), "title": candidate.get("title"), - "claimed": True, - "claimed_status": pipeline_board.STATUS_UNDER_REVIEW, } @@ -1079,8 +1074,12 @@ def build_review_pipeline_context( review_candidate_fetcher: Callable[[str], list[dict]] | None = None, pr_context_builder: Callable[[str, int], dict] | None = None, review_preparer: Callable[[str, int], dict] | None = None, - mover: Callable[[str, str], None] | None = None, ) -> dict: + """Build review-pipeline context (read-only, no board move). + + The agent is responsible for claiming the item (moving to Under review) + after it has verified the PR is review-ready and is about to start work. + """ review_candidate_fetcher = review_candidate_fetcher or fetch_review_candidates pr_context_builder = pr_context_builder or pipeline_pr.build_pr_context review_preparer = review_preparer or ( @@ -1089,7 +1088,6 @@ def build_review_pipeline_context( pr_number=pr_number, ) ) - mover = mover or pipeline_board.move_item candidates = review_candidate_fetcher(repo) if not candidates: @@ -1123,9 +1121,6 @@ def build_review_pipeline_context( ) if matching_ambiguous is not None: selection = build_ambiguous_selection(matching_ambiguous, pr_number=pr_number) - mover(str(matching_ambiguous["item_id"]), pipeline_board.STATUS_UNDER_REVIEW) - selection["claimed"] = True - selection["claimed_status"] = pipeline_board.STATUS_UNDER_REVIEW return build_ready_result( skill="review-pipeline", selection=selection, @@ -1140,7 +1135,7 @@ def build_review_pipeline_context( if candidate.get("eligibility") != "eligible": return build_status_result("review-pipeline", status="empty") - selection = _selection_from_candidate(candidate, mover=mover) + selection = _selection_from_candidate(candidate) selected_pr_number = int(selection["pr_number"]) return build_ready_result( skill="review-pipeline", diff --git a/scripts/test_pipeline_skill_context.py b/scripts/test_pipeline_skill_context.py index f716cc43d..c68aac934 100644 --- a/scripts/test_pipeline_skill_context.py +++ b/scripts/test_pipeline_skill_context.py @@ -507,8 +507,6 @@ def test_build_review_pipeline_context_reports_manual_choice_for_ambiguous_card( ) def test_build_review_pipeline_context_disambiguates_explicit_pr_choice(self) -> None: - moves: list[tuple[str, str]] = [] - result = pipeline_skill_context.build_review_pipeline_context( repo="CodingThrust/problem-reductions", pr_number=173, @@ -528,7 +526,6 @@ def test_build_review_pipeline_context_disambiguates_explicit_pr_choice(self) -> ], } ], - mover=lambda item_id, status: moves.append((item_id, status)), pr_context_builder=lambda repo, pr_number: { "number": pr_number, "title": "Fix #109: Add LCS reduction", @@ -539,7 +536,6 @@ def test_build_review_pipeline_context_disambiguates_explicit_pr_choice(self) -> }, ) - self.assertEqual(moves, [("PVTI_10", "Under review")]) self.assertEqual( result, { @@ -552,8 +548,6 @@ def test_build_review_pipeline_context_disambiguates_explicit_pr_choice(self) -> "pr_number": 173, "status": "Review pool", "title": "[Model] LongestCommonSubsequence", - "claimed": True, - "claimed_status": "Under review", }, "pr": { "number": 173, @@ -567,8 +561,6 @@ def test_build_review_pipeline_context_disambiguates_explicit_pr_choice(self) -> ) def test_build_review_pipeline_context_returns_ready_bundle_for_eligible_pr(self) -> None: - moves: list[tuple[str, str]] = [] - result = pipeline_skill_context.build_review_pipeline_context( repo="CodingThrust/problem-reductions", pr_number=None, @@ -584,7 +576,6 @@ def test_build_review_pipeline_context_returns_ready_bundle_for_eligible_pr(self "reason": "open PR", } ], - mover=lambda item_id, status: moves.append((item_id, status)), pr_context_builder=lambda repo, pr_number: { "number": pr_number, "comments": {"counts": {"human_inline_comments": 0}}, @@ -595,10 +586,9 @@ def test_build_review_pipeline_context_returns_ready_bundle_for_eligible_pr(self }, ) - self.assertEqual(moves, [("PVTI_11", "Under review")]) self.assertEqual(result["status"], "ready") self.assertEqual(result["selection"]["pr_number"], 570) - self.assertEqual(result["selection"]["claimed"], True) + self.assertNotIn("claimed", result["selection"]) self.assertEqual( result["pr"], {"number": 570, "comments": {"counts": {"human_inline_comments": 0}}}, @@ -608,9 +598,8 @@ def test_build_review_pipeline_context_returns_ready_bundle_for_eligible_pr(self {"ready": True, "checkout": {"worktree_dir": "/tmp/review-pr-570"}}, ) - def test_build_review_pipeline_context_claims_via_mover(self) -> None: - moves: list[tuple[str, str]] = [] - + def test_build_review_pipeline_context_does_not_claim(self) -> None: + """Context generation is read-only — the agent claims after verifying.""" result = pipeline_skill_context.build_review_pipeline_context( repo="CodingThrust/problem-reductions", pr_number=None, @@ -626,18 +615,16 @@ def test_build_review_pipeline_context_claims_via_mover(self) -> None: "reason": "open PR", } ], - mover=lambda item_id, status: moves.append((item_id, status)), pr_context_builder=lambda repo, pr_number: {"number": pr_number}, review_preparer=lambda repo, pr_number: {"ready": True}, ) - self.assertEqual(moves, [("PVTI_11", "Under review")]) self.assertEqual(result["status"], "ready") self.assertEqual(result["selection"]["pr_number"], 570) + self.assertNotIn("claimed", result["selection"]) - def test_build_review_pipeline_context_explicit_pr_claims_via_mover(self) -> None: - moves: list[tuple[str, str]] = [] - + def test_build_review_pipeline_context_explicit_pr_does_not_claim(self) -> None: + """Explicit PR selection is also read-only.""" result = pipeline_skill_context.build_review_pipeline_context( repo="CodingThrust/problem-reductions", pr_number=570, @@ -653,14 +640,13 @@ def test_build_review_pipeline_context_explicit_pr_claims_via_mover(self) -> Non "reason": "open PR", } ], - mover=lambda item_id, status: moves.append((item_id, status)), pr_context_builder=lambda repo, pr_number: {"number": pr_number}, review_preparer=lambda repo, pr_number: {"ready": True}, ) - self.assertEqual(moves, [("PVTI_11", "Under review")]) self.assertEqual(result["status"], "ready") self.assertEqual(result["selection"]["pr_number"], 570) + self.assertNotIn("claimed", result["selection"]) def test_build_final_review_context_reports_empty_queue(self) -> None: result = pipeline_skill_context.build_final_review_context( diff --git a/src/example_db/fixtures/examples.json b/src/example_db/fixtures/examples.json deleted file mode 100644 index c143c6e05..000000000 --- a/src/example_db/fixtures/examples.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "models": [ - {"problem":"BMF","variant":{},"instance":{"k":2,"m":3,"matrix":[[true,true,false],[true,true,true],[false,true,true]],"n":3},"samples":[{"config":[1,0,1,1,0,1,1,1,0,0,1,1],"metric":{"Valid":0}}],"optimal":[{"config":[0,1,1,1,1,0,0,1,1,1,1,0],"metric":{"Valid":0}},{"config":[1,0,1,1,0,1,1,1,0,0,1,1],"metric":{"Valid":0}}]}, - {"problem":"BalancedCompleteBipartiteSubgraph","variant":{},"instance":{"graph":{"edges":[[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2],[3,0],[3,1],[3,3]],"left_size":4,"right_size":4},"k":3},"samples":[{"config":[1,1,1,0,1,1,1,0],"metric":true}],"optimal":[{"config":[1,1,1,0,1,1,1,0],"metric":true}]}, - {"problem":"BicliqueCover","variant":{},"instance":{"graph":{"edges":[[0,0],[0,1],[1,1],[1,2]],"left_size":2,"right_size":3},"k":2},"samples":[{"config":[1,0,0,1,1,0,1,1,0,1],"metric":{"Valid":6}}],"optimal":[{"config":[0,1,0,1,0,1,0,1,0,1],"metric":{"Valid":5}},{"config":[1,0,1,0,1,0,1,0,1,0],"metric":{"Valid":5}}]}, - {"problem":"BiconnectivityAugmentation","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"budget":4,"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[4,5,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}},"potential_weights":[[0,2,1],[0,3,2],[0,4,3],[1,3,1],[1,4,2],[1,5,3],[2,4,1],[2,5,2],[3,5,1]]},"samples":[{"config":[1,0,0,1,0,0,1,0,1],"metric":true}],"optimal":[{"config":[0,0,1,0,0,0,0,0,1],"metric":true},{"config":[0,1,0,0,0,0,0,1,0],"metric":true},{"config":[0,1,0,0,0,0,1,0,1],"metric":true},{"config":[1,0,0,0,0,1,0,0,0],"metric":true},{"config":[1,0,0,0,1,0,0,0,1],"metric":true},{"config":[1,0,0,1,0,0,0,1,0],"metric":true},{"config":[1,0,0,1,0,0,1,0,1],"metric":true}]}, - {"problem":"BoundedComponentSpanningForest","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[4,5,null],[5,6,null],[6,7,null],[0,7,null],[1,5,null],[2,6,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null]}},"max_components":3,"max_weight":6,"weights":[2,3,1,2,3,1,2,1]},"samples":[{"config":[0,0,1,1,1,2,2,0],"metric":true}],"optimal":[{"config":[0,0,0,1,1,1,2,2],"metric":true},{"config":[0,0,0,1,1,2,2,2],"metric":true},{"config":[0,0,0,2,2,1,1,1],"metric":true},{"config":[0,0,0,2,2,2,1,1],"metric":true},{"config":[0,0,1,1,1,0,2,2],"metric":true},{"config":[0,0,1,1,1,2,2,0],"metric":true},{"config":[0,0,1,1,1,2,2,2],"metric":true},{"config":[0,0,1,1,2,0,1,1],"metric":true},{"config":[0,0,1,1,2,1,1,0],"metric":true},{"config":[0,0,1,1,2,2,1,0],"metric":true},{"config":[0,0,1,1,2,2,1,1],"metric":true},{"config":[0,0,1,1,2,2,2,0],"metric":true},{"config":[0,0,1,2,2,0,1,1],"metric":true},{"config":[0,0,1,2,2,1,1,0],"metric":true},{"config":[0,0,1,2,2,1,1,1],"metric":true},{"config":[0,0,1,2,2,2,1,0],"metric":true},{"config":[0,0,1,2,2,2,1,1],"metric":true},{"config":[0,0,2,1,1,0,2,2],"metric":true},{"config":[0,0,2,1,1,1,2,0],"metric":true},{"config":[0,0,2,1,1,1,2,2],"metric":true},{"config":[0,0,2,1,1,2,2,0],"metric":true},{"config":[0,0,2,1,1,2,2,2],"metric":true},{"config":[0,0,2,2,1,0,2,2],"metric":true},{"config":[0,0,2,2,1,1,1,0],"metric":true},{"config":[0,0,2,2,1,1,2,0],"metric":true},{"config":[0,0,2,2,1,1,2,2],"metric":true},{"config":[0,0,2,2,1,2,2,0],"metric":true},{"config":[0,0,2,2,2,0,1,1],"metric":true},{"config":[0,0,2,2,2,1,1,0],"metric":true},{"config":[0,0,2,2,2,1,1,1],"metric":true},{"config":[0,1,0,2,2,1,0,0],"metric":true},{"config":[0,1,0,2,2,2,0,0],"metric":true},{"config":[0,1,1,1,2,0,0,0],"metric":true},{"config":[0,1,1,1,2,2,0,0],"metric":true},{"config":[0,1,1,1,2,2,2,0],"metric":true},{"config":[0,1,1,2,2,0,0,0],"metric":true},{"config":[0,1,1,2,2,1,0,0],"metric":true},{"config":[0,1,1,2,2,2,0,0],"metric":true},{"config":[0,1,1,2,2,2,1,0],"metric":true},{"config":[0,1,2,2,2,0,0,0],"metric":true},{"config":[0,1,2,2,2,1,0,0],"metric":true},{"config":[0,1,2,2,2,1,1,0],"metric":true},{"config":[0,2,0,1,1,1,0,0],"metric":true},{"config":[0,2,0,1,1,2,0,0],"metric":true},{"config":[0,2,1,1,1,0,0,0],"metric":true},{"config":[0,2,1,1,1,2,0,0],"metric":true},{"config":[0,2,1,1,1,2,2,0],"metric":true},{"config":[0,2,2,1,1,0,0,0],"metric":true},{"config":[0,2,2,1,1,1,0,0],"metric":true},{"config":[0,2,2,1,1,1,2,0],"metric":true},{"config":[0,2,2,1,1,2,0,0],"metric":true},{"config":[0,2,2,2,1,0,0,0],"metric":true},{"config":[0,2,2,2,1,1,0,0],"metric":true},{"config":[0,2,2,2,1,1,1,0],"metric":true},{"config":[1,0,0,0,2,1,1,1],"metric":true},{"config":[1,0,0,0,2,2,1,1],"metric":true},{"config":[1,0,0,0,2,2,2,1],"metric":true},{"config":[1,0,0,2,2,0,1,1],"metric":true},{"config":[1,0,0,2,2,1,1,1],"metric":true},{"config":[1,0,0,2,2,2,0,1],"metric":true},{"config":[1,0,0,2,2,2,1,1],"metric":true},{"config":[1,0,1,2,2,0,1,1],"metric":true},{"config":[1,0,1,2,2,2,1,1],"metric":true},{"config":[1,0,2,2,2,0,0,1],"metric":true},{"config":[1,0,2,2,2,0,1,1],"metric":true},{"config":[1,0,2,2,2,1,1,1],"metric":true},{"config":[1,1,0,0,0,1,2,2],"metric":true},{"config":[1,1,0,0,0,2,2,1],"metric":true},{"config":[1,1,0,0,0,2,2,2],"metric":true},{"config":[1,1,0,0,2,0,0,1],"metric":true},{"config":[1,1,0,0,2,1,0,0],"metric":true},{"config":[1,1,0,0,2,2,0,0],"metric":true},{"config":[1,1,0,0,2,2,0,1],"metric":true},{"config":[1,1,0,0,2,2,2,1],"metric":true},{"config":[1,1,0,2,2,0,0,0],"metric":true},{"config":[1,1,0,2,2,0,0,1],"metric":true},{"config":[1,1,0,2,2,1,0,0],"metric":true},{"config":[1,1,0,2,2,2,0,0],"metric":true},{"config":[1,1,0,2,2,2,0,1],"metric":true},{"config":[1,1,1,0,0,0,2,2],"metric":true},{"config":[1,1,1,0,0,2,2,2],"metric":true},{"config":[1,1,1,2,2,0,0,0],"metric":true},{"config":[1,1,1,2,2,2,0,0],"metric":true},{"config":[1,1,2,0,0,0,2,1],"metric":true},{"config":[1,1,2,0,0,0,2,2],"metric":true},{"config":[1,1,2,0,0,1,2,2],"metric":true},{"config":[1,1,2,0,0,2,2,1],"metric":true},{"config":[1,1,2,0,0,2,2,2],"metric":true},{"config":[1,1,2,2,0,0,0,1],"metric":true},{"config":[1,1,2,2,0,0,2,1],"metric":true},{"config":[1,1,2,2,0,0,2,2],"metric":true},{"config":[1,1,2,2,0,1,2,2],"metric":true},{"config":[1,1,2,2,0,2,2,1],"metric":true},{"config":[1,1,2,2,2,0,0,0],"metric":true},{"config":[1,1,2,2,2,0,0,1],"metric":true},{"config":[1,1,2,2,2,1,0,0],"metric":true},{"config":[1,2,0,0,0,1,1,1],"metric":true},{"config":[1,2,0,0,0,2,1,1],"metric":true},{"config":[1,2,0,0,0,2,2,1],"metric":true},{"config":[1,2,1,0,0,0,1,1],"metric":true},{"config":[1,2,1,0,0,2,1,1],"metric":true},{"config":[1,2,2,0,0,0,1,1],"metric":true},{"config":[1,2,2,0,0,0,2,1],"metric":true},{"config":[1,2,2,0,0,1,1,1],"metric":true},{"config":[1,2,2,0,0,2,1,1],"metric":true},{"config":[1,2,2,2,0,0,0,1],"metric":true},{"config":[1,2,2,2,0,0,1,1],"metric":true},{"config":[1,2,2,2,0,1,1,1],"metric":true},{"config":[2,0,0,0,1,1,1,2],"metric":true},{"config":[2,0,0,0,1,1,2,2],"metric":true},{"config":[2,0,0,0,1,2,2,2],"metric":true},{"config":[2,0,0,1,1,0,2,2],"metric":true},{"config":[2,0,0,1,1,1,0,2],"metric":true},{"config":[2,0,0,1,1,1,2,2],"metric":true},{"config":[2,0,0,1,1,2,2,2],"metric":true},{"config":[2,0,1,1,1,0,0,2],"metric":true},{"config":[2,0,1,1,1,0,2,2],"metric":true},{"config":[2,0,1,1,1,2,2,2],"metric":true},{"config":[2,0,2,1,1,0,2,2],"metric":true},{"config":[2,0,2,1,1,1,2,2],"metric":true},{"config":[2,1,0,0,0,1,1,2],"metric":true},{"config":[2,1,0,0,0,1,2,2],"metric":true},{"config":[2,1,0,0,0,2,2,2],"metric":true},{"config":[2,1,1,0,0,0,1,2],"metric":true},{"config":[2,1,1,0,0,0,2,2],"metric":true},{"config":[2,1,1,0,0,1,2,2],"metric":true},{"config":[2,1,1,0,0,2,2,2],"metric":true},{"config":[2,1,1,1,0,0,0,2],"metric":true},{"config":[2,1,1,1,0,0,2,2],"metric":true},{"config":[2,1,1,1,0,2,2,2],"metric":true},{"config":[2,1,2,0,0,0,2,2],"metric":true},{"config":[2,1,2,0,0,1,2,2],"metric":true},{"config":[2,2,0,0,0,1,1,1],"metric":true},{"config":[2,2,0,0,0,1,1,2],"metric":true},{"config":[2,2,0,0,0,2,1,1],"metric":true},{"config":[2,2,0,0,1,0,0,2],"metric":true},{"config":[2,2,0,0,1,1,0,0],"metric":true},{"config":[2,2,0,0,1,1,0,2],"metric":true},{"config":[2,2,0,0,1,1,1,2],"metric":true},{"config":[2,2,0,0,1,2,0,0],"metric":true},{"config":[2,2,0,1,1,0,0,0],"metric":true},{"config":[2,2,0,1,1,0,0,2],"metric":true},{"config":[2,2,0,1,1,1,0,0],"metric":true},{"config":[2,2,0,1,1,1,0,2],"metric":true},{"config":[2,2,0,1,1,2,0,0],"metric":true},{"config":[2,2,1,0,0,0,1,1],"metric":true},{"config":[2,2,1,0,0,0,1,2],"metric":true},{"config":[2,2,1,0,0,1,1,1],"metric":true},{"config":[2,2,1,0,0,1,1,2],"metric":true},{"config":[2,2,1,0,0,2,1,1],"metric":true},{"config":[2,2,1,1,0,0,0,2],"metric":true},{"config":[2,2,1,1,0,0,1,1],"metric":true},{"config":[2,2,1,1,0,0,1,2],"metric":true},{"config":[2,2,1,1,0,1,1,2],"metric":true},{"config":[2,2,1,1,0,2,1,1],"metric":true},{"config":[2,2,1,1,1,0,0,0],"metric":true},{"config":[2,2,1,1,1,0,0,2],"metric":true},{"config":[2,2,1,1,1,2,0,0],"metric":true},{"config":[2,2,2,0,0,0,1,1],"metric":true},{"config":[2,2,2,0,0,1,1,1],"metric":true},{"config":[2,2,2,1,1,0,0,0],"metric":true},{"config":[2,2,2,1,1,1,0,0],"metric":true}]}, - {"problem":"CircuitSAT","variant":{},"instance":{"circuit":{"assignments":[{"expr":{"op":{"And":[{"op":{"Var":"x1"}},{"op":{"Var":"x2"}}]}},"outputs":["a"]},{"expr":{"op":{"Or":[{"op":{"Var":"x1"}},{"op":{"Var":"x2"}}]}},"outputs":["b"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a"}},{"op":{"Var":"b"}}]}},"outputs":["c"]}]},"variables":["a","b","c","x1","x2"]},"samples":[{"config":[0,1,1,0,1],"metric":true},{"config":[0,1,1,1,0],"metric":true}],"optimal":[{"config":[0,0,0,0,0],"metric":true},{"config":[0,1,1,0,1],"metric":true},{"config":[0,1,1,1,0],"metric":true},{"config":[1,1,0,1,1],"metric":true}]}, - {"problem":"ClosestVectorProblem","variant":{"weight":"i32"},"instance":{"basis":[[2,0],[1,2]],"bounds":[{"lower":-2,"upper":4},{"lower":-2,"upper":4}],"target":[2.8,1.5]},"samples":[{"config":[3,3],"metric":{"Valid":0.5385164807134505}}],"optimal":[{"config":[3,3],"metric":{"Valid":0.5385164807134505}}]}, - {"problem":"ComparativeContainment","variant":{"weight":"i32"},"instance":{"r_sets":[[0,1,2,3],[0,1]],"r_weights":[2,5],"s_sets":[[0,1,2,3],[2,3]],"s_weights":[3,6],"universe_size":4},"samples":[{"config":[1,0,0,0],"metric":true}],"optimal":[{"config":[0,1,0,0],"metric":true},{"config":[1,0,0,0],"metric":true},{"config":[1,1,0,0],"metric":true}]}, - {"problem":"ConsecutiveSets","variant":{},"instance":{"alphabet_size":6,"bound_k":6,"subsets":[[0,4],[2,4],[2,5],[1,5],[1,3]]},"samples":[{"config":[0,4,2,5,1,3],"metric":true}],"optimal":[{"config":[0,4,2,5,1,3],"metric":true},{"config":[3,1,5,2,4,0],"metric":true}]}, - {"problem":"DirectedTwoCommodityIntegralFlow","variant":{},"instance":{"capacities":[1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"directed","edges":[[0,2,null],[0,3,null],[1,2,null],[1,3,null],[2,4,null],[2,5,null],[3,4,null],[3,5,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}},"requirement_1":1,"requirement_2":1,"sink_1":4,"sink_2":5,"source_1":0,"source_2":1},"samples":[{"config":[1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1],"metric":true}],"optimal":[{"config":[0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[0,0,0,1,0,0,1,0,0,1,1,0,0,1,0,1],"metric":true},{"config":[0,0,0,1,0,0,1,0,0,1,1,0,1,0,0,1],"metric":true},{"config":[0,0,0,1,0,0,1,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,0,0,1,0,0,1,0,1,0,1,0,1,1,0,0],"metric":true},{"config":[0,0,0,1,0,0,1,0,1,1,0,0,0,1,0,1],"metric":true},{"config":[0,0,0,1,0,0,1,0,1,1,0,0,1,0,0,1],"metric":true},{"config":[0,0,0,1,0,0,1,0,1,1,1,0,1,1,0,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,0,1,0,1,0,0,1,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,0,0,1,0,1,0,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,0,0,1,0,1,1,0],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,1,0,0,0,1,0,1],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,1,0,0,0,1,1,0],"metric":true},{"config":[0,0,1,0,1,0,0,0,1,1,0,1,0,1,1,1],"metric":true},{"config":[0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,1],"metric":true},{"config":[0,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0],"metric":true},{"config":[0,0,1,1,1,0,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[0,0,1,1,1,0,1,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,0,1,1,1,0,1,0,1,1,0,0,0,1,0,1],"metric":true},{"config":[0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[0,1,0,0,0,0,1,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[0,1,0,0,0,0,1,0,0,0,1,1,0,1,0,1],"metric":true},{"config":[0,1,0,0,0,0,1,0,0,0,1,1,1,0,0,1],"metric":true},{"config":[0,1,0,0,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,1,0,1,0,1],"metric":true},{"config":[0,1,0,0,0,0,1,0,1,0,0,1,1,0,0,1],"metric":true},{"config":[0,1,0,0,0,0,1,0,1,0,1,0,1,1,0,0],"metric":true},{"config":[0,1,0,0,0,0,1,0,1,0,1,1,1,1,0,1],"metric":true},{"config":[0,1,0,1,0,0,1,1,0,0,1,0,0,1,0,0],"metric":true},{"config":[0,1,0,1,0,0,1,1,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,1,0,1,0,0,1,1,1,0,1,0,1,1,0,0],"metric":true},{"config":[0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1],"metric":true},{"config":[0,1,1,0,1,0,0,1,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0],"metric":true},{"config":[0,1,1,0,1,0,1,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[0,1,1,0,1,0,1,0,1,0,0,0,0,1,0,0],"metric":true},{"config":[0,1,1,0,1,0,1,0,1,0,0,1,0,1,0,1],"metric":true},{"config":[0,1,1,1,1,0,1,1,1,0,0,0,0,1,0,0],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,0,1,1,0,1,0,1],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,0,1,1,0,1,1,0],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,1,0,1,0,0,1,1],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,1,1,0,0,1,0,1],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,1,1,0,0,1,1,0],"metric":true},{"config":[1,0,0,0,1,0,0,0,0,1,1,1,0,1,1,1],"metric":true},{"config":[1,0,0,1,0,1,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1],"metric":true},{"config":[1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,0,1,1,0,0,1,0,1,1,0,0,1,1,0],"metric":true},{"config":[1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,0,1,1,0,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[1,0,0,1,1,0,1,0,0,1,1,0,0,1,0,1],"metric":true},{"config":[1,0,1,0,1,1,0,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[1,0,1,0,1,1,0,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[1,0,1,0,1,1,0,0,0,1,0,1,0,0,1,1],"metric":true},{"config":[1,0,1,1,1,1,1,0,0,1,0,0,0,0,0,1],"metric":true},{"config":[1,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,1],"metric":true},{"config":[1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,1,0,0,1,0,0,1,0,0,1,1,0,1,1,0],"metric":true},{"config":[1,1,0,0,1,0,1,0,0,0,0,1,0,0,0,1],"metric":true},{"config":[1,1,0,0,1,0,1,0,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,1,0,0,1,0,1,0,0,0,1,1,0,1,0,1],"metric":true},{"config":[1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0],"metric":true},{"config":[1,1,1,0,1,1,1,0,0,0,0,1,0,0,0,1],"metric":true}]}, - {"problem":"ExactCoverBy3Sets","variant":{},"instance":{"subsets":[[0,1,2],[0,2,4],[3,4,5],[3,5,7],[6,7,8],[1,4,6],[2,5,8]],"universe_size":9},"samples":[{"config":[1,0,1,0,1,0,0],"metric":true}],"optimal":[{"config":[1,0,1,0,1,0,0],"metric":true}]}, - {"problem":"Factoring","variant":{},"instance":{"m":2,"n":3,"target":15},"samples":[{"config":[1,1,1,0,1],"metric":{"Valid":0}}],"optimal":[{"config":[1,1,1,0,1],"metric":{"Valid":0}}]}, - {"problem":"HamiltonianCircuit","variant":{"graph":"SimpleGraph"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,0,null],[3,4,null],[4,5,null],[5,3,null],[0,3,null],[1,4,null],[2,5,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}}},"samples":[{"config":[0,1,2,5,4,3],"metric":true}],"optimal":[{"config":[0,1,2,5,4,3],"metric":true},{"config":[0,1,4,3,5,2],"metric":true},{"config":[0,2,1,4,5,3],"metric":true},{"config":[0,2,5,3,4,1],"metric":true},{"config":[0,3,4,5,2,1],"metric":true},{"config":[0,3,5,4,1,2],"metric":true},{"config":[1,0,2,5,3,4],"metric":true},{"config":[1,0,3,4,5,2],"metric":true},{"config":[1,2,0,3,5,4],"metric":true},{"config":[1,2,5,4,3,0],"metric":true},{"config":[1,4,3,5,2,0],"metric":true},{"config":[1,4,5,3,0,2],"metric":true},{"config":[2,0,1,4,3,5],"metric":true},{"config":[2,0,3,5,4,1],"metric":true},{"config":[2,1,0,3,4,5],"metric":true},{"config":[2,1,4,5,3,0],"metric":true},{"config":[2,5,3,4,1,0],"metric":true},{"config":[2,5,4,3,0,1],"metric":true},{"config":[3,0,1,2,5,4],"metric":true},{"config":[3,0,2,1,4,5],"metric":true},{"config":[3,4,1,0,2,5],"metric":true},{"config":[3,4,5,2,1,0],"metric":true},{"config":[3,5,2,0,1,4],"metric":true},{"config":[3,5,4,1,2,0],"metric":true},{"config":[4,1,0,2,5,3],"metric":true},{"config":[4,1,2,0,3,5],"metric":true},{"config":[4,3,0,1,2,5],"metric":true},{"config":[4,3,5,2,0,1],"metric":true},{"config":[4,5,2,1,0,3],"metric":true},{"config":[4,5,3,0,2,1],"metric":true},{"config":[5,2,0,1,4,3],"metric":true},{"config":[5,2,1,0,3,4],"metric":true},{"config":[5,3,0,2,1,4],"metric":true},{"config":[5,3,4,1,0,2],"metric":true},{"config":[5,4,1,2,0,3],"metric":true},{"config":[5,4,3,0,1,2],"metric":true}]}, - {"problem":"HamiltonianPath","variant":{"graph":"SimpleGraph"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[1,3,null],[2,3,null],[3,4,null],[3,5,null],[4,2,null],[5,1,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}}},"samples":[{"config":[0,2,4,3,1,5],"metric":true}],"optimal":[{"config":[0,1,5,3,2,4],"metric":true},{"config":[0,1,5,3,4,2],"metric":true},{"config":[0,2,4,3,1,5],"metric":true},{"config":[0,2,4,3,5,1],"metric":true},{"config":[1,0,2,4,3,5],"metric":true},{"config":[1,5,3,4,2,0],"metric":true},{"config":[2,0,1,5,3,4],"metric":true},{"config":[2,4,3,5,1,0],"metric":true},{"config":[3,4,2,0,1,5],"metric":true},{"config":[3,5,1,0,2,4],"metric":true},{"config":[4,2,0,1,3,5],"metric":true},{"config":[4,2,0,1,5,3],"metric":true},{"config":[4,2,3,5,1,0],"metric":true},{"config":[4,3,2,0,1,5],"metric":true},{"config":[4,3,5,1,0,2],"metric":true},{"config":[5,1,0,2,3,4],"metric":true},{"config":[5,1,0,2,4,3],"metric":true},{"config":[5,1,3,4,2,0],"metric":true},{"config":[5,3,1,0,2,4],"metric":true},{"config":[5,3,4,2,0,1],"metric":true}]}, - {"problem":"ILP","variant":{"variable":"i32"},"instance":{"constraints":[{"cmp":"Le","rhs":5.0,"terms":[[0,1.0],[1,1.0]]},{"cmp":"Le","rhs":28.0,"terms":[[0,4.0],[1,7.0]]}],"num_vars":2,"objective":[[0,-5.0],[1,-6.0]],"sense":"Minimize"},"samples":[{"config":[0,4],"metric":{"Valid":-24.0}}],"optimal":[{"config":[3,2],"metric":{"Valid":-27.0}}]}, - {"problem":"IsomorphicSpanningTree","variant":{},"instance":{"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]}},"tree":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[0,3,null]],"node_holes":[],"nodes":[null,null,null,null]}}},"samples":[{"config":[0,1,2,3],"metric":true}],"optimal":[{"config":[0,1,2,3],"metric":true},{"config":[0,1,3,2],"metric":true},{"config":[0,2,1,3],"metric":true},{"config":[0,2,3,1],"metric":true},{"config":[0,3,1,2],"metric":true},{"config":[0,3,2,1],"metric":true},{"config":[1,0,2,3],"metric":true},{"config":[1,0,3,2],"metric":true},{"config":[1,2,0,3],"metric":true},{"config":[1,2,3,0],"metric":true},{"config":[1,3,0,2],"metric":true},{"config":[1,3,2,0],"metric":true},{"config":[2,0,1,3],"metric":true},{"config":[2,0,3,1],"metric":true},{"config":[2,1,0,3],"metric":true},{"config":[2,1,3,0],"metric":true},{"config":[2,3,0,1],"metric":true},{"config":[2,3,1,0],"metric":true},{"config":[3,0,1,2],"metric":true},{"config":[3,0,2,1],"metric":true},{"config":[3,1,0,2],"metric":true},{"config":[3,1,2,0],"metric":true},{"config":[3,2,0,1],"metric":true},{"config":[3,2,1,0],"metric":true}]}, - {"problem":"KColoring","variant":{"graph":"SimpleGraph","k":"K3"},"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},"samples":[{"config":[0,1,1,0,2],"metric":true}],"optimal":[{"config":[0,1,1,0,2],"metric":true},{"config":[0,1,1,2,0],"metric":true},{"config":[0,1,2,0,1],"metric":true},{"config":[0,2,1,0,2],"metric":true},{"config":[0,2,2,0,1],"metric":true},{"config":[0,2,2,1,0],"metric":true},{"config":[1,0,0,1,2],"metric":true},{"config":[1,0,0,2,1],"metric":true},{"config":[1,0,2,1,0],"metric":true},{"config":[1,2,0,1,2],"metric":true},{"config":[1,2,2,0,1],"metric":true},{"config":[1,2,2,1,0],"metric":true},{"config":[2,0,0,1,2],"metric":true},{"config":[2,0,0,2,1],"metric":true},{"config":[2,0,1,2,0],"metric":true},{"config":[2,1,0,2,1],"metric":true},{"config":[2,1,1,0,2],"metric":true},{"config":[2,1,1,2,0],"metric":true}]}, - {"problem":"KSatisfiability","variant":{"k":"K3"},"instance":{"clauses":[{"literals":[1,2,3]},{"literals":[-1,-2,3]},{"literals":[1,-2,-3]}],"num_vars":3},"samples":[{"config":[1,0,1],"metric":true}],"optimal":[{"config":[0,0,1],"metric":true},{"config":[0,1,0],"metric":true},{"config":[1,0,0],"metric":true},{"config":[1,0,1],"metric":true},{"config":[1,1,1],"metric":true}]}, - {"problem":"KthBestSpanningTree","variant":{"weight":"i32"},"instance":{"bound":4,"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]}},"k":2,"weights":[1,1,2,2,2,3]},"samples":[{"config":[1,1,1,0,0,0,1,1,0,0,1,0],"metric":true},{"config":[0,0,0,0,0,0,0,0,0,0,0,0],"metric":false}],"optimal":[{"config":[1,1,0,0,1,0,1,1,1,0,0,0],"metric":true},{"config":[1,1,1,0,0,0,1,1,0,0,1,0],"metric":true}]}, - {"problem":"LengthBoundedDisjointPaths","variant":{"graph":"SimpleGraph"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,6,null],[0,2,null],[2,3,null],[3,6,null],[0,4,null],[4,5,null],[5,6,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null]}},"max_length":3,"num_paths_required":2,"sink":6,"source":0},"samples":[{"config":[1,1,0,0,0,0,1,1,0,1,1,0,0,1],"metric":true}],"optimal":[{"config":[1,0,0,0,1,1,1,1,0,1,1,0,0,1],"metric":true},{"config":[1,0,0,0,1,1,1,1,1,0,0,0,0,1],"metric":true},{"config":[1,0,1,1,0,0,1,1,0,0,0,1,1,1],"metric":true},{"config":[1,0,1,1,0,0,1,1,1,0,0,0,0,1],"metric":true},{"config":[1,1,0,0,0,0,1,1,0,0,0,1,1,1],"metric":true},{"config":[1,1,0,0,0,0,1,1,0,1,1,0,0,1],"metric":true}]}, - {"problem":"LongestCommonSubsequence","variant":{},"instance":{"alphabet_size":2,"bound":3,"strings":[[0,1,0,1,1,0],[1,0,0,1,0,1],[0,0,1,0,1,1],[1,1,0,0,1,0],[0,1,0,1,0,1],[1,0,1,0,1,0]]},"samples":[{"config":[0,1,0],"metric":true}],"optimal":[{"config":[0,0,0],"metric":true},{"config":[0,0,1],"metric":true},{"config":[0,1,0],"metric":true},{"config":[1,0,1],"metric":true},{"config":[1,1,1],"metric":true}]}, - {"problem":"MaxCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1],"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]}}},"samples":[{"config":[1,0,0,1,0],"metric":{"Valid":5}}],"optimal":[{"config":[0,1,1,0,0],"metric":{"Valid":5}},{"config":[0,1,1,0,1],"metric":{"Valid":5}},{"config":[1,0,0,1,0],"metric":{"Valid":5}},{"config":[1,0,0,1,1],"metric":{"Valid":5}}]}, - {"problem":"MaximalIS","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]},"samples":[{"config":[0,1,0,1,0],"metric":{"Valid":2}},{"config":[1,0,1,0,1],"metric":{"Valid":3}}],"optimal":[{"config":[1,0,1,0,1],"metric":{"Valid":3}}]}, - {"problem":"MaximumClique","variant":{"graph":"SimpleGraph","weight":"i32"},"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]}},"weights":[1,1,1,1,1]},"samples":[{"config":[0,0,1,1,1],"metric":{"Valid":3}}],"optimal":[{"config":[0,0,1,1,1],"metric":{"Valid":3}}]}, - {"problem":"MaximumIndependentSet","variant":{"graph":"SimpleGraph","weight":"One"},"instance":{"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[4,0,null],[5,7,null],[7,9,null],[9,6,null],[6,8,null],[8,5,null],[0,5,null],[1,6,null],[2,7,null],[3,8,null],[4,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]},"samples":[{"config":[0,1,0,1,0,1,0,0,0,1],"metric":{"Valid":4}}],"optimal":[{"config":[0,0,1,0,1,1,1,0,0,0],"metric":{"Valid":4}},{"config":[0,1,0,0,1,0,0,1,1,0],"metric":{"Valid":4}},{"config":[0,1,0,1,0,1,0,0,0,1],"metric":{"Valid":4}},{"config":[1,0,0,1,0,0,1,1,0,0],"metric":{"Valid":4}},{"config":[1,0,1,0,0,0,0,0,1,1],"metric":{"Valid":4}}]}, - {"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],[4,0,null],[5,7,null],[7,9,null],[9,6,null],[6,8,null],[8,5,null],[0,5,null],[1,6,null],[2,7,null],[3,8,null],[4,9,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null]}},"weights":[5,1,1,1,1,3,1,1,1,3]},"samples":[{"config":[1,0,1,0,0,0,0,0,1,1],"metric":{"Valid":10}}],"optimal":[{"config":[1,0,1,0,0,0,0,0,1,1],"metric":{"Valid":10}}]}, - {"problem":"MaximumMatching","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,1,1,1,1,1],"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]}}},"samples":[{"config":[1,0,0,0,1,0],"metric":{"Valid":2}}],"optimal":[{"config":[0,0,1,0,1,0],"metric":{"Valid":2}},{"config":[0,1,0,0,0,1],"metric":{"Valid":2}},{"config":[0,1,1,0,0,0],"metric":{"Valid":2}},{"config":[1,0,0,0,0,1],"metric":{"Valid":2}},{"config":[1,0,0,0,1,0],"metric":{"Valid":2}},{"config":[1,0,0,1,0,0],"metric":{"Valid":2}}]}, - {"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1],[1,2],[2,3],[3,4]],"weights":[1,1,1,1]},"samples":[{"config":[1,0,1,0],"metric":{"Valid":2}}],"optimal":[{"config":[0,1,0,1],"metric":{"Valid":2}},{"config":[1,0,0,1],"metric":{"Valid":2}},{"config":[1,0,1,0],"metric":{"Valid":2}}]}, - {"problem":"MinimumCardinalityKey","variant":{},"instance":{"bound_k":2,"dependencies":[[[0,1],[2]],[[0,2],[3]],[[1,3],[4]],[[2,4],[5]]],"num_attributes":6},"samples":[{"config":[1,1,0,0,0,0],"metric":true}],"optimal":[{"config":[1,1,0,0,0,0],"metric":true}]}, - {"problem":"MinimumDominatingSet","variant":{"graph":"SimpleGraph","weight":"i32"},"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]}},"weights":[1,1,1,1,1]},"samples":[{"config":[0,0,1,1,0],"metric":{"Valid":2}}],"optimal":[{"config":[0,0,1,1,0],"metric":{"Valid":2}},{"config":[0,1,0,0,1],"metric":{"Valid":2}},{"config":[0,1,0,1,0],"metric":{"Valid":2}},{"config":[0,1,1,0,0],"metric":{"Valid":2}},{"config":[1,0,0,0,1],"metric":{"Valid":2}},{"config":[1,0,0,1,0],"metric":{"Valid":2}},{"config":[1,0,1,0,0],"metric":{"Valid":2}}]}, - {"problem":"MinimumFeedbackVertexSet","variant":{"weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"directed","edges":[[0,1,null],[1,2,null],[2,0,null],[0,3,null],[3,4,null],[4,1,null],[4,2,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"weights":[1,1,1,1,1]},"samples":[{"config":[1,0,0,0,0],"metric":{"Valid":1}}],"optimal":[{"config":[0,0,1,0,0],"metric":{"Valid":1}},{"config":[1,0,0,0,0],"metric":{"Valid":1}}]}, - {"problem":"MinimumMultiwayCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[2,3,1,2,4,5],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[0,4,null],[1,3,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"terminals":[0,2,4]},"samples":[{"config":[1,0,0,1,1,0],"metric":{"Valid":8}}],"optimal":[{"config":[1,0,0,1,1,0],"metric":{"Valid":8}}]}, - {"problem":"MinimumSetCovering","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[1,3],[2,3,4]],"universe_size":5,"weights":[1,1,1]},"samples":[{"config":[1,0,1],"metric":{"Valid":2}}],"optimal":[{"config":[1,0,1],"metric":{"Valid":2}}]}, - {"problem":"MinimumSumMulticenter","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_lengths":[1,1,1,1,1,1,1,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[4,5,null],[5,6,null],[0,6,null],[2,5,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null]}},"k":2,"vertex_weights":[1,1,1,1,1,1,1]},"samples":[{"config":[0,0,1,0,0,1,0],"metric":{"Valid":6}}],"optimal":[{"config":[0,0,0,1,0,0,1],"metric":{"Valid":6}},{"config":[0,0,1,0,0,0,1],"metric":{"Valid":6}},{"config":[0,0,1,0,0,1,0],"metric":{"Valid":6}},{"config":[0,1,0,0,0,1,0],"metric":{"Valid":6}},{"config":[0,1,0,0,1,0,0],"metric":{"Valid":6}},{"config":[1,0,0,0,0,1,0],"metric":{"Valid":6}},{"config":[1,0,0,0,1,0,0],"metric":{"Valid":6}},{"config":[1,0,0,1,0,0,0],"metric":{"Valid":6}},{"config":[1,0,1,0,0,0,0],"metric":{"Valid":6}}]}, - {"problem":"MinimumTardinessSequencing","variant":{},"instance":{"deadlines":[2,3,1,4],"num_tasks":4,"precedences":[[0,2]]},"samples":[{"config":[0,0,0,0],"metric":{"Valid":1}}],"optimal":[{"config":[0,0,0,0],"metric":{"Valid":1}},{"config":[0,0,1,0],"metric":{"Valid":1}},{"config":[0,1,0,0],"metric":{"Valid":1}},{"config":[0,2,0,0],"metric":{"Valid":1}},{"config":[1,0,0,0],"metric":{"Valid":1}},{"config":[1,0,1,0],"metric":{"Valid":1}},{"config":[3,0,0,0],"metric":{"Valid":1}}]}, - {"problem":"MinimumVertexCover","variant":{"graph":"SimpleGraph","weight":"i32"},"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]}},"weights":[1,1,1,1,1]},"samples":[{"config":[1,0,0,1,1],"metric":{"Valid":3}}],"optimal":[{"config":[0,1,1,0,1],"metric":{"Valid":3}},{"config":[0,1,1,1,0],"metric":{"Valid":3}},{"config":[1,0,0,1,1],"metric":{"Valid":3}},{"config":[1,0,1,1,0],"metric":{"Valid":3}}]}, - {"problem":"MultipleChoiceBranching","variant":{"weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"directed","edges":[[0,1,null],[0,2,null],[1,3,null],[2,3,null],[1,4,null],[3,5,null],[4,5,null],[2,4,null]],"node_holes":[],"nodes":[null,null,null,null,null,null]}},"partition":[[0,1],[2,3],[4,7],[5,6]],"threshold":10,"weights":[3,2,4,1,2,3,1,3]},"samples":[{"config":[1,0,1,0,0,1,0,1],"metric":true}],"optimal":[{"config":[0,0,1,0,0,1,0,1],"metric":true},{"config":[0,1,1,0,0,0,1,1],"metric":true},{"config":[0,1,1,0,0,1,0,1],"metric":true},{"config":[0,1,1,0,1,1,0,0],"metric":true},{"config":[1,0,0,1,0,1,0,1],"metric":true},{"config":[1,0,1,0,0,0,0,1],"metric":true},{"config":[1,0,1,0,0,0,1,1],"metric":true},{"config":[1,0,1,0,0,1,0,0],"metric":true},{"config":[1,0,1,0,0,1,0,1],"metric":true},{"config":[1,0,1,0,1,0,1,0],"metric":true},{"config":[1,0,1,0,1,1,0,0],"metric":true}]}, - {"problem":"MultiprocessorScheduling","variant":{},"instance":{"deadline":10,"lengths":[4,5,3,2,6],"num_processors":2},"samples":[{"config":[0,0,0,0,0],"metric":false},{"config":[0,1,1,1,0],"metric":true}],"optimal":[{"config":[0,1,1,1,0],"metric":true}]}, - {"problem":"PaintShop","variant":{},"instance":{"car_labels":["A","B","C"],"is_first":[true,true,false,true,false,false],"num_cars":3,"sequence_indices":[0,1,0,2,1,2]},"samples":[{"config":[0,0,1],"metric":{"Valid":2}}],"optimal":[{"config":[0,0,1],"metric":{"Valid":2}},{"config":[0,1,1],"metric":{"Valid":2}},{"config":[1,0,0],"metric":{"Valid":2}},{"config":[1,1,0],"metric":{"Valid":2}}]}, - {"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":"SequencingWithReleaseTimesAndDeadlines","variant":{},"instance":{"deadlines":[5,6,10,3,12],"lengths":[3,2,4,1,2],"release_times":[0,1,5,0,8]},"samples":[{"config":[3,0,0,0,0],"metric":true}],"optimal":[{"config":[3,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}}]}, - {"problem":"StaffScheduling","variant":{},"instance":{"num_workers":4,"requirements":[2,2,2,3,3,2,1],"schedules":[[true,true,true,true,true,false,false],[false,true,true,true,true,true,false],[false,false,true,true,true,true,true],[true,false,false,true,true,true,true],[true,true,false,false,true,true,true]],"shifts_per_schedule":5},"samples":[{"config":[1,1,1,1,0],"metric":true}],"optimal":[{"config":[0,1,1,1,1],"metric":true},{"config":[0,2,0,1,1],"metric":true},{"config":[0,2,0,2,0],"metric":true},{"config":[1,0,1,1,1],"metric":true},{"config":[1,0,2,0,1],"metric":true},{"config":[1,1,0,1,0],"metric":true},{"config":[1,1,0,1,1],"metric":true},{"config":[1,1,0,2,0],"metric":true},{"config":[1,1,1,0,1],"metric":true},{"config":[1,1,1,1,0],"metric":true},{"config":[1,2,0,0,1],"metric":true},{"config":[1,2,0,1,0],"metric":true},{"config":[2,0,0,1,1],"metric":true},{"config":[2,0,0,2,0],"metric":true},{"config":[2,0,1,0,1],"metric":true},{"config":[2,0,1,1,0],"metric":true},{"config":[2,0,2,0,0],"metric":true},{"config":[2,1,0,0,1],"metric":true},{"config":[2,1,0,1,0],"metric":true},{"config":[2,1,1,0,0],"metric":true}]}, - {"problem":"SteinerTree","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[2,5,2,1,5,6,1],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,3,null],[1,2,null],[1,3,null],[2,3,null],[2,4,null],[3,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"terminals":[0,2,4]},"samples":[{"config":[1,0,1,1,0,0,1],"metric":{"Valid":6}}],"optimal":[{"config":[1,0,1,1,0,0,1],"metric":{"Valid":6}}]}, - {"problem":"StringToStringCorrection","variant":{},"instance":{"alphabet_size":4,"bound":2,"source":[0,1,2,3,1,0],"target":[0,1,3,2,1]},"samples":[{"config":[8,5],"metric":true}],"optimal":[{"config":[5,7],"metric":true},{"config":[8,5],"metric":true}]}, - {"problem":"StrongConnectivityAugmentation","variant":{"weight":"i32"},"instance":{"bound":8,"candidate_arcs":[[4,0,10],[4,3,3],[4,2,3],[4,1,3],[3,0,7],[3,1,3],[2,0,7],[2,1,3],[1,0,5]],"graph":{"inner":{"edge_property":"directed","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null]],"node_holes":[],"nodes":[null,null,null,null,null]}}},"samples":[{"config":[0,0,0,1,0,0,0,0,1],"metric":true},{"config":[0,0,0,0,0,0,0,0,0],"metric":false}],"optimal":[{"config":[0,0,0,1,0,0,0,0,1],"metric":true}]}, - {"problem":"SumOfSquaresPartition","variant":{},"instance":{"bound":240,"num_groups":3,"sizes":[5,3,8,2,7,1]},"samples":[{"config":[1,2,0,1,2,0],"metric":true}],"optimal":[{"config":[0,0,1,0,2,0],"metric":true},{"config":[0,0,1,0,2,1],"metric":true},{"config":[0,0,1,0,2,2],"metric":true},{"config":[0,0,1,1,2,0],"metric":true},{"config":[0,0,1,1,2,1],"metric":true},{"config":[0,0,1,1,2,2],"metric":true},{"config":[0,0,1,2,2,0],"metric":true},{"config":[0,0,1,2,2,1],"metric":true},{"config":[0,0,1,2,2,2],"metric":true},{"config":[0,0,2,0,1,0],"metric":true},{"config":[0,0,2,0,1,1],"metric":true},{"config":[0,0,2,0,1,2],"metric":true},{"config":[0,0,2,1,1,0],"metric":true},{"config":[0,0,2,1,1,1],"metric":true},{"config":[0,0,2,1,1,2],"metric":true},{"config":[0,0,2,2,1,0],"metric":true},{"config":[0,0,2,2,1,1],"metric":true},{"config":[0,0,2,2,1,2],"metric":true},{"config":[0,1,1,0,2,0],"metric":true},{"config":[0,1,1,0,2,2],"metric":true},{"config":[0,1,1,2,2,0],"metric":true},{"config":[0,1,2,0,1,0],"metric":true},{"config":[0,1,2,0,1,1],"metric":true},{"config":[0,1,2,0,1,2],"metric":true},{"config":[0,1,2,2,1,0],"metric":true},{"config":[0,2,1,0,2,0],"metric":true},{"config":[0,2,1,0,2,1],"metric":true},{"config":[0,2,1,0,2,2],"metric":true},{"config":[0,2,1,1,2,0],"metric":true},{"config":[0,2,2,0,1,0],"metric":true},{"config":[0,2,2,0,1,1],"metric":true},{"config":[0,2,2,1,1,0],"metric":true},{"config":[1,0,0,1,2,1],"metric":true},{"config":[1,0,0,1,2,2],"metric":true},{"config":[1,0,0,2,2,1],"metric":true},{"config":[1,0,2,1,0,0],"metric":true},{"config":[1,0,2,1,0,1],"metric":true},{"config":[1,0,2,1,0,2],"metric":true},{"config":[1,0,2,2,0,1],"metric":true},{"config":[1,1,0,0,2,0],"metric":true},{"config":[1,1,0,0,2,1],"metric":true},{"config":[1,1,0,0,2,2],"metric":true},{"config":[1,1,0,1,2,0],"metric":true},{"config":[1,1,0,1,2,1],"metric":true},{"config":[1,1,0,1,2,2],"metric":true},{"config":[1,1,0,2,2,0],"metric":true},{"config":[1,1,0,2,2,1],"metric":true},{"config":[1,1,0,2,2,2],"metric":true},{"config":[1,1,2,0,0,0],"metric":true},{"config":[1,1,2,0,0,1],"metric":true},{"config":[1,1,2,0,0,2],"metric":true},{"config":[1,1,2,1,0,0],"metric":true},{"config":[1,1,2,1,0,1],"metric":true},{"config":[1,1,2,1,0,2],"metric":true},{"config":[1,1,2,2,0,0],"metric":true},{"config":[1,1,2,2,0,1],"metric":true},{"config":[1,1,2,2,0,2],"metric":true},{"config":[1,2,0,0,2,1],"metric":true},{"config":[1,2,0,1,2,0],"metric":true},{"config":[1,2,0,1,2,1],"metric":true},{"config":[1,2,0,1,2,2],"metric":true},{"config":[1,2,2,0,0,1],"metric":true},{"config":[1,2,2,1,0,0],"metric":true},{"config":[1,2,2,1,0,1],"metric":true},{"config":[2,0,0,1,1,2],"metric":true},{"config":[2,0,0,2,1,1],"metric":true},{"config":[2,0,0,2,1,2],"metric":true},{"config":[2,0,1,1,0,2],"metric":true},{"config":[2,0,1,2,0,0],"metric":true},{"config":[2,0,1,2,0,1],"metric":true},{"config":[2,0,1,2,0,2],"metric":true},{"config":[2,1,0,0,1,2],"metric":true},{"config":[2,1,0,2,1,0],"metric":true},{"config":[2,1,0,2,1,1],"metric":true},{"config":[2,1,0,2,1,2],"metric":true},{"config":[2,1,1,0,0,2],"metric":true},{"config":[2,1,1,2,0,0],"metric":true},{"config":[2,1,1,2,0,2],"metric":true},{"config":[2,2,0,0,1,0],"metric":true},{"config":[2,2,0,0,1,1],"metric":true},{"config":[2,2,0,0,1,2],"metric":true},{"config":[2,2,0,1,1,0],"metric":true},{"config":[2,2,0,1,1,1],"metric":true},{"config":[2,2,0,1,1,2],"metric":true},{"config":[2,2,0,2,1,0],"metric":true},{"config":[2,2,0,2,1,1],"metric":true},{"config":[2,2,0,2,1,2],"metric":true},{"config":[2,2,1,0,0,0],"metric":true},{"config":[2,2,1,0,0,1],"metric":true},{"config":[2,2,1,0,0,2],"metric":true},{"config":[2,2,1,1,0,0],"metric":true},{"config":[2,2,1,1,0,1],"metric":true},{"config":[2,2,1,1,0,2],"metric":true},{"config":[2,2,1,2,0,0],"metric":true},{"config":[2,2,1,2,0,1],"metric":true},{"config":[2,2,1,2,0,2],"metric":true}]}, - {"problem":"TravelingSalesman","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[1,3,2,2,3,1],"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]}}},"samples":[{"config":[1,0,1,1,0,1],"metric":{"Valid":6}}],"optimal":[{"config":[1,0,1,1,0,1],"metric":{"Valid":6}}]}, - {"problem":"UndirectedTwoCommodityIntegralFlow","variant":{},"instance":{"capacities":[1,1,2],"graph":{"inner":{"edge_property":"undirected","edges":[[0,2,null],[1,2,null],[2,3,null]],"node_holes":[],"nodes":[null,null,null,null]}},"requirement_1":1,"requirement_2":1,"sink_1":3,"sink_2":3,"source_1":0,"source_2":1},"samples":[{"config":[1,0,0,0,0,0,1,0,1,0,1,0],"metric":true}],"optimal":[{"config":[0,0,1,0,1,0,0,0,1,0,1,0],"metric":true},{"config":[1,0,0,0,0,0,1,0,1,0,1,0],"metric":true}]} - ], - "rules": [ - {"source":{"problem":"BinPacking","variant":{"weight":"i32"},"instance":{"capacity":10,"sizes":[6,5,5,4,3]}},"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],[4,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[5,1.0],[6,1.0],[7,1.0],[8,1.0],[9,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[10,1.0],[11,1.0],[12,1.0],[13,1.0],[14,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[15,1.0],[16,1.0],[17,1.0],[18,1.0],[19,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[20,1.0],[21,1.0],[22,1.0],[23,1.0],[24,1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[0,6.0],[5,5.0],[10,5.0],[15,4.0],[20,3.0],[25,-10.0]]},{"cmp":"Le","rhs":0.0,"terms":[[1,6.0],[6,5.0],[11,5.0],[16,4.0],[21,3.0],[26,-10.0]]},{"cmp":"Le","rhs":0.0,"terms":[[2,6.0],[7,5.0],[12,5.0],[17,4.0],[22,3.0],[27,-10.0]]},{"cmp":"Le","rhs":0.0,"terms":[[3,6.0],[8,5.0],[13,5.0],[18,4.0],[23,3.0],[28,-10.0]]},{"cmp":"Le","rhs":0.0,"terms":[[4,6.0],[9,5.0],[14,5.0],[19,4.0],[24,3.0],[29,-10.0]]}],"num_vars":30,"objective":[[25,1.0],[26,1.0],[27,1.0],[28,1.0],[29,1.0]],"sense":"Minimize"}},"solutions":[{"source_config":[2,1,0,0,2],"target_config":[0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,0,1,1,1,0,0]}]}, - {"source":{"problem":"CircuitSAT","variant":{},"instance":{"circuit":{"assignments":[{"expr":{"op":{"Xor":[{"op":{"Var":"a"}},{"op":{"Var":"b"}}]}},"outputs":["t"]},{"expr":{"op":{"Xor":[{"op":{"Var":"t"}},{"op":{"Var":"cin"}}]}},"outputs":["sum"]},{"expr":{"op":{"And":[{"op":{"Var":"a"}},{"op":{"Var":"b"}}]}},"outputs":["ab"]},{"expr":{"op":{"And":[{"op":{"Var":"cin"}},{"op":{"Var":"t"}}]}},"outputs":["cin_t"]},{"expr":{"op":{"Or":[{"op":{"Var":"ab"}},{"op":{"Var":"cin_t"}}]}},"outputs":["cout"]}]},"variables":["a","ab","b","cin","cin_t","cout","sum","t"]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":0.0,"terms":[[8,1.0],[0,-1.0],[2,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[8,1.0],[0,-1.0],[2,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[8,1.0],[0,1.0],[2,-1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[8,1.0],[0,1.0],[2,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[7,1.0],[8,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[9,1.0],[7,-1.0],[3,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[9,1.0],[7,-1.0],[3,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[9,1.0],[7,1.0],[3,-1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[9,1.0],[7,1.0],[3,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[6,1.0],[9,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[10,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[10,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[10,1.0],[0,-1.0],[2,-1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[1,1.0],[10,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[11,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[11,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[11,1.0],[3,-1.0],[7,-1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[4,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[12,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[12,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[12,1.0],[1,-1.0],[4,-1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[5,1.0],[12,-1.0]]}],"num_vars":13,"objective":[],"sense":"Minimize"}},"solutions":[{"source_config":[0,0,0,0,0,0,0,0],"target_config":[0,0,0,0,0,0,0,0,0,0,0,0,0]}]}, - {"source":{"problem":"CircuitSAT","variant":{},"instance":{"circuit":{"assignments":[{"expr":{"op":{"Xor":[{"op":{"Var":"a"}},{"op":{"Var":"b"}}]}},"outputs":["t"]},{"expr":{"op":{"Xor":[{"op":{"Var":"t"}},{"op":{"Var":"cin"}}]}},"outputs":["sum"]},{"expr":{"op":{"And":[{"op":{"Var":"a"}},{"op":{"Var":"b"}}]}},"outputs":["ab"]},{"expr":{"op":{"And":[{"op":{"Var":"cin"}},{"op":{"Var":"t"}}]}},"outputs":["cin_t"]},{"expr":{"op":{"Or":[{"op":{"Var":"ab"}},{"op":{"Var":"cin_t"}}]}},"outputs":["cout"]}]},"variables":["a","ab","b","cin","cin_t","cout","sum","t"]}},"target":{"problem":"SpinGlass","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"couplings":[2,-1,-2,-2,-1,-2,-2,2,-4,2,-1,-2,-2,-1,-2,-2,2,-4,-4,1,-2,-4,-2,-4],"fields":[-2,-2,1,2,-2,-2,1,2,0,2,1,2,1,-2,0],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[0,2,null],[0,3,null],[0,9,null],[1,2,null],[1,3,null],[1,9,null],[2,3,null],[2,4,null],[4,5,null],[4,6,null],[4,7,null],[4,11,null],[5,6,null],[5,7,null],[5,11,null],[6,7,null],[6,8,null],[9,10,null],[10,12,null],[10,13,null],[11,12,null],[12,13,null],[13,14,null]],"node_holes":[],"nodes":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}}}},"solutions":[{"source_config":[0,0,0,0,0,0,0,0],"target_config":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}]}, - {"source":{"problem":"Factoring","variant":{},"instance":{"m":3,"n":3,"target":35}},"target":{"problem":"CircuitSAT","variant":{},"instance":{"circuit":{"assignments":[{"expr":{"op":{"And":[{"op":{"Var":"p1"}},{"op":{"Var":"q1"}}]}},"outputs":["a_1_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_1_1"}},{"op":{"Const":false}}]}},"outputs":["axs_1_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_1_1"}},{"op":{"Const":false}}]}},"outputs":["s1_1"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_1_1"}},{"op":{"Const":false}}]}},"outputs":["axsc_1_1"]},{"expr":{"op":{"And":[{"op":{"Var":"a_1_1"}},{"op":{"Const":false}}]}},"outputs":["as_1_1"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_1_1"}},{"op":{"Var":"as_1_1"}}]}},"outputs":["c1_1"]},{"expr":{"op":{"And":[{"op":{"Var":"p1"}},{"op":{"Var":"q2"}}]}},"outputs":["a_1_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_1_2"}},{"op":{"Const":false}}]}},"outputs":["axs_1_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_1_2"}},{"op":{"Var":"c1_1"}}]}},"outputs":["s1_2"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_1_2"}},{"op":{"Var":"c1_1"}}]}},"outputs":["axsc_1_2"]},{"expr":{"op":{"And":[{"op":{"Var":"a_1_2"}},{"op":{"Const":false}}]}},"outputs":["as_1_2"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_1_2"}},{"op":{"Var":"as_1_2"}}]}},"outputs":["c1_2"]},{"expr":{"op":{"And":[{"op":{"Var":"p1"}},{"op":{"Var":"q3"}}]}},"outputs":["a_1_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_1_3"}},{"op":{"Const":false}}]}},"outputs":["axs_1_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_1_3"}},{"op":{"Var":"c1_2"}}]}},"outputs":["s1_3"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_1_3"}},{"op":{"Var":"c1_2"}}]}},"outputs":["axsc_1_3"]},{"expr":{"op":{"And":[{"op":{"Var":"a_1_3"}},{"op":{"Const":false}}]}},"outputs":["as_1_3"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_1_3"}},{"op":{"Var":"as_1_3"}}]}},"outputs":["c1_3"]},{"expr":{"op":{"And":[{"op":{"Var":"p2"}},{"op":{"Var":"q1"}}]}},"outputs":["a_2_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_2_1"}},{"op":{"Var":"s1_2"}}]}},"outputs":["axs_2_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_2_1"}},{"op":{"Const":false}}]}},"outputs":["s2_1"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_2_1"}},{"op":{"Const":false}}]}},"outputs":["axsc_2_1"]},{"expr":{"op":{"And":[{"op":{"Var":"a_2_1"}},{"op":{"Var":"s1_2"}}]}},"outputs":["as_2_1"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_2_1"}},{"op":{"Var":"as_2_1"}}]}},"outputs":["c2_1"]},{"expr":{"op":{"And":[{"op":{"Var":"p2"}},{"op":{"Var":"q2"}}]}},"outputs":["a_2_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_2_2"}},{"op":{"Var":"s1_3"}}]}},"outputs":["axs_2_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_2_2"}},{"op":{"Var":"c2_1"}}]}},"outputs":["s2_2"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_2_2"}},{"op":{"Var":"c2_1"}}]}},"outputs":["axsc_2_2"]},{"expr":{"op":{"And":[{"op":{"Var":"a_2_2"}},{"op":{"Var":"s1_3"}}]}},"outputs":["as_2_2"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_2_2"}},{"op":{"Var":"as_2_2"}}]}},"outputs":["c2_2"]},{"expr":{"op":{"And":[{"op":{"Var":"p2"}},{"op":{"Var":"q3"}}]}},"outputs":["a_2_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_2_3"}},{"op":{"Var":"c1_3"}}]}},"outputs":["axs_2_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_2_3"}},{"op":{"Var":"c2_2"}}]}},"outputs":["s2_3"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_2_3"}},{"op":{"Var":"c2_2"}}]}},"outputs":["axsc_2_3"]},{"expr":{"op":{"And":[{"op":{"Var":"a_2_3"}},{"op":{"Var":"c1_3"}}]}},"outputs":["as_2_3"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_2_3"}},{"op":{"Var":"as_2_3"}}]}},"outputs":["c2_3"]},{"expr":{"op":{"And":[{"op":{"Var":"p3"}},{"op":{"Var":"q1"}}]}},"outputs":["a_3_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_3_1"}},{"op":{"Var":"s2_2"}}]}},"outputs":["axs_3_1"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_3_1"}},{"op":{"Const":false}}]}},"outputs":["s3_1"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_3_1"}},{"op":{"Const":false}}]}},"outputs":["axsc_3_1"]},{"expr":{"op":{"And":[{"op":{"Var":"a_3_1"}},{"op":{"Var":"s2_2"}}]}},"outputs":["as_3_1"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_3_1"}},{"op":{"Var":"as_3_1"}}]}},"outputs":["c3_1"]},{"expr":{"op":{"And":[{"op":{"Var":"p3"}},{"op":{"Var":"q2"}}]}},"outputs":["a_3_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_3_2"}},{"op":{"Var":"s2_3"}}]}},"outputs":["axs_3_2"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_3_2"}},{"op":{"Var":"c3_1"}}]}},"outputs":["s3_2"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_3_2"}},{"op":{"Var":"c3_1"}}]}},"outputs":["axsc_3_2"]},{"expr":{"op":{"And":[{"op":{"Var":"a_3_2"}},{"op":{"Var":"s2_3"}}]}},"outputs":["as_3_2"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_3_2"}},{"op":{"Var":"as_3_2"}}]}},"outputs":["c3_2"]},{"expr":{"op":{"And":[{"op":{"Var":"p3"}},{"op":{"Var":"q3"}}]}},"outputs":["a_3_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"a_3_3"}},{"op":{"Var":"c2_3"}}]}},"outputs":["axs_3_3"]},{"expr":{"op":{"Xor":[{"op":{"Var":"axs_3_3"}},{"op":{"Var":"c3_2"}}]}},"outputs":["s3_3"]},{"expr":{"op":{"And":[{"op":{"Var":"axs_3_3"}},{"op":{"Var":"c3_2"}}]}},"outputs":["axsc_3_3"]},{"expr":{"op":{"And":[{"op":{"Var":"a_3_3"}},{"op":{"Var":"c2_3"}}]}},"outputs":["as_3_3"]},{"expr":{"op":{"Or":[{"op":{"Var":"axsc_3_3"}},{"op":{"Var":"as_3_3"}}]}},"outputs":["c3_3"]},{"expr":{"op":{"Const":true}},"outputs":["s1_1"]},{"expr":{"op":{"Const":true}},"outputs":["s2_1"]},{"expr":{"op":{"Const":false}},"outputs":["s3_1"]},{"expr":{"op":{"Const":false}},"outputs":["s3_2"]},{"expr":{"op":{"Const":false}},"outputs":["s3_3"]},{"expr":{"op":{"Const":true}},"outputs":["c3_3"]}]},"variables":["a_1_1","a_1_2","a_1_3","a_2_1","a_2_2","a_2_3","a_3_1","a_3_2","a_3_3","as_1_1","as_1_2","as_1_3","as_2_1","as_2_2","as_2_3","as_3_1","as_3_2","as_3_3","axs_1_1","axs_1_2","axs_1_3","axs_2_1","axs_2_2","axs_2_3","axs_3_1","axs_3_2","axs_3_3","axsc_1_1","axsc_1_2","axsc_1_3","axsc_2_1","axsc_2_2","axsc_2_3","axsc_3_1","axsc_3_2","axsc_3_3","c1_1","c1_2","c1_3","c2_1","c2_2","c2_3","c3_1","c3_2","c3_3","p1","p2","p3","q1","q2","q3","s1_1","s1_2","s1_3","s2_1","s2_2","s2_3","s3_1","s3_2","s3_3"]}},"solutions":[{"source_config":[1,0,1,1,1,1],"target_config":[1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0]}]}, - {"source":{"problem":"Factoring","variant":{},"instance":{"m":3,"n":3,"target":35}},"target":{"problem":"ILP","variant":{"variable":"i32"},"instance":{"constraints":[{"cmp":"Le","rhs":0.0,"terms":[[6,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[6,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[6,1.0],[0,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[7,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[7,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[7,1.0],[0,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[8,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[8,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[8,1.0],[0,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[9,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[9,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[9,1.0],[1,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[10,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[10,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[10,1.0],[1,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[11,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[11,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[11,1.0],[1,-1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[12,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[12,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[12,1.0],[2,-1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[13,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[13,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[13,1.0],[2,-1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[14,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[14,1.0],[5,-1.0]]},{"cmp":"Ge","rhs":-1.0,"terms":[[14,1.0],[2,-1.0],[5,-1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[6,1.0],[15,-2.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[7,1.0],[9,1.0],[15,1.0],[16,-2.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[8,1.0],[10,1.0],[12,1.0],[16,1.0],[17,-2.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[11,1.0],[13,1.0],[17,1.0],[18,-2.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[14,1.0],[18,1.0],[19,-2.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[19,1.0],[20,-2.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[20,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[3,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[5,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[15,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[16,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[17,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[18,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[19,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0]]},{"cmp":"Le","rhs":3.0,"terms":[[20,1.0]]}],"num_vars":21,"objective":[],"sense":"Minimize"}},"solutions":[{"source_config":[1,0,1,1,1,1],"target_config":[1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1,1,0]}]}, - {"source":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":10.0,"terms":[[0,3.0],[1,2.0],[2,5.0],[3,4.0],[4,2.0],[5,3.0]]},{"cmp":"Le","rhs":2.0,"terms":[[0,1.0],[1,1.0],[2,1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[3,1.0],[4,1.0],[5,1.0]]}],"num_vars":6,"objective":[[0,10.0],[1,7.0],[2,12.0],[3,8.0],[4,6.0],[5,9.0]],"sense":"Maximize"}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-3628.0,938.0,2144.0,1608.0,804.0,1206.0,402.0,804.0,1608.0,3216.0,134.0,268.0,0.0,0.0],[0.0,-2620.0,1474.0,1072.0,536.0,804.0,268.0,536.0,1072.0,2144.0,134.0,268.0,0.0,0.0],[0.0,0.0,-5238.0,2680.0,1340.0,2010.0,670.0,1340.0,2680.0,5360.0,134.0,268.0,0.0,0.0],[0.0,0.0,0.0,-4497.0,1206.0,1742.0,536.0,1072.0,2144.0,4288.0,0.0,0.0,134.0,268.0],[0.0,0.0,0.0,0.0,-2619.0,938.0,268.0,536.0,1072.0,2144.0,0.0,0.0,134.0,268.0],[0.0,0.0,0.0,0.0,0.0,-3627.0,402.0,804.0,1608.0,3216.0,0.0,0.0,134.0,268.0],[0.0,0.0,0.0,0.0,0.0,0.0,-1273.0,268.0,536.0,1072.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2412.0,1072.0,2144.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,-4288.0,4288.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,-6432.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,-201.0,268.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,-268.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,-201.0,268.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,-268.0]],"num_vars":14}},"solutions":[{"source_config":[1,1,0,0,1,1],"target_config":[1,1,0,0,1,1,0,0,0,0,0,0,0,0]}]}, - {"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,-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":{"alphabet_size":3,"bound":2,"strings":[[0,1,2],[1,0,2]]}},"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":[[12,1.0],[13,1.0],[14,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[9,1.0],[10,1.0],[11,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[15,1.0],[16,1.0],[17,1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[6,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[7,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[8,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[12,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[13,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[14,1.0],[5,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[9,1.0],[1,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[10,1.0],[0,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[11,1.0],[2,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[15,1.0],[4,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[16,1.0],[3,-1.0]]},{"cmp":"Le","rhs":0.0,"terms":[[17,1.0],[5,-1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[6,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[7,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[7,1.0],[13,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[12,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[13,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[8,1.0],[14,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[9,1.0],[15,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[10,1.0],[15,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[10,1.0],[16,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[11,1.0],[15,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[11,1.0],[16,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[11,1.0],[17,1.0]]}],"num_vars":18,"objective":[],"sense":"Minimize"}},"solutions":[{"source_config":[0,2],"target_config":[1,0,0,0,0,1,1,0,0,0,1,0,0,0,1,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":[0,1,0,1,0,1,0,0,0,1],"target_config":[0,1,0,1,0,1,0,0,0,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":"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":"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]}]}, - {"source":{"problem":"MaximumSetPacking","variant":{"weight":"f64"},"instance":{"sets":[[0,1,2],[2,3,4],[4,5,6],[6,7,0],[1,3,5],[0,4,7]],"weights":[1.0,1.0,1.0,1.0,1.0,1.0]}},"target":{"problem":"QUBO","variant":{"weight":"f64"},"instance":{"matrix":[[-1.0,7.0,0.0,7.0,7.0,7.0],[0.0,-1.0,7.0,0.0,7.0,7.0],[0.0,0.0,-1.0,7.0,7.0,7.0],[0.0,0.0,0.0,-1.0,0.0,7.0],[0.0,0.0,0.0,0.0,-1.0,0.0],[0.0,0.0,0.0,0.0,0.0,-1.0]],"num_vars":6}},"solutions":[{"source_config":[0,0,0,1,1,0],"target_config":[0,0,0,1,1,0]}]}, - {"source":{"problem":"MaximumSetPacking","variant":{"weight":"i32"},"instance":{"sets":[[0,1,2],[2,3,4],[4,5,6],[6,7,0],[1,3,5],[0,4,7]],"weights":[1,1,1,1,1,1]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[3,1.0],[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[0,1.0],[1,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0],[2,1.0],[5,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[4,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0],[3,1.0]]},{"cmp":"Le","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":"Maximize"}},"solutions":[{"source_config":[0,0,0,1,1,0],"target_config":[0,0,0,1,1,0]}]}, - {"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":"MinimumFeedbackVertexSet","variant":{"weight":"i32"},"instance":{"graph":{"inner":{"edge_property":"directed","edges":[[0,1,null],[1,2,null],[2,0,null]],"node_holes":[],"nodes":[null,null,null]}},"weights":[1,1,1]}},"target":{"problem":"ILP","variant":{"variable":"i32"},"instance":{"constraints":[{"cmp":"Le","rhs":1.0,"terms":[[0,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[1,1.0]]},{"cmp":"Le","rhs":1.0,"terms":[[2,1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[3,1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[4,1.0]]},{"cmp":"Le","rhs":2.0,"terms":[[5,1.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[4,1.0],[3,-1.0],[0,3.0],[1,3.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[5,1.0],[4,-1.0],[1,3.0],[2,3.0]]},{"cmp":"Ge","rhs":1.0,"terms":[[3,1.0],[5,-1.0],[2,3.0],[0,3.0]]}],"num_vars":6,"objective":[[0,1.0],[1,1.0],[2,1.0]],"sense":"Minimize"}},"solutions":[{"source_config":[0,1,0],"target_config":[0,1,0,1,0,0]}]}, - {"source":{"problem":"MinimumMultiwayCut","variant":{"graph":"SimpleGraph","weight":"i32"},"instance":{"edge_weights":[2,3,1,2,4,5],"graph":{"inner":{"edge_property":"undirected","edges":[[0,1,null],[1,2,null],[2,3,null],[3,4,null],[0,4,null],[1,3,null]],"node_holes":[],"nodes":[null,null,null,null,null]}},"terminals":[0,2,4]}},"target":{"problem":"ILP","variant":{"variable":"bool"},"instance":{"constraints":[{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[7,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[14,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[5,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[10,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[2,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[12,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[4,1.0]]},{"cmp":"Eq","rhs":0.0,"terms":[[9,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[0,1.0],[5,1.0],[10,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[1,1.0],[6,1.0],[11,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[2,1.0],[7,1.0],[12,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[3,1.0],[8,1.0],[13,1.0]]},{"cmp":"Eq","rhs":1.0,"terms":[[4,1.0],[9,1.0],[14,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[0,-1.0],[1,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[0,1.0],[1,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[5,-1.0],[6,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[5,1.0],[6,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[10,-1.0],[11,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[15,1.0],[10,1.0],[11,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[1,-1.0],[2,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[1,1.0],[2,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[6,-1.0],[7,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[6,1.0],[7,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[11,-1.0],[12,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[16,1.0],[11,1.0],[12,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[2,-1.0],[3,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[2,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[7,-1.0],[8,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[7,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[12,-1.0],[13,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[17,1.0],[12,1.0],[13,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[3,-1.0],[4,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[3,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[8,-1.0],[9,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[8,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[13,-1.0],[14,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[18,1.0],[13,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[0,-1.0],[4,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[0,1.0],[4,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[5,-1.0],[9,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[5,1.0],[9,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[10,-1.0],[14,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[19,1.0],[10,1.0],[14,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[1,-1.0],[3,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[1,1.0],[3,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[6,-1.0],[8,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[6,1.0],[8,-1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[11,-1.0],[13,1.0]]},{"cmp":"Ge","rhs":0.0,"terms":[[20,1.0],[11,1.0],[13,-1.0]]}],"num_vars":21,"objective":[[15,2.0],[16,3.0],[17,1.0],[18,2.0],[19,4.0],[20,5.0]],"sense":"Minimize"}},"solutions":[{"source_config":[1,0,0,1,1,0],"target_config":[1,0,0,0,0,0,1,1,1,0,0,0,0,0,1,1,0,0,1,1,0]}]}, - {"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":"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,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]}]} - ] -} diff --git a/src/example_db/mod.rs b/src/example_db/mod.rs index 756499d9b..adddc3df4 100644 --- a/src/example_db/mod.rs +++ b/src/example_db/mod.rs @@ -1,17 +1,11 @@ //! Canonical example database assembly. //! -//! The example database has two layers: +//! Each model and rule has a canonical example spec that stores both the +//! problem instance and its known optimal solution. The database is computed +//! from these specs on demand — no static fixture file. //! -//! - **Fixtures** (`fixtures/examples.json`): pre-computed expected results -//! embedded at compile time as a wrapped JSON object. These are the "stored -//! expected results" used for fast export and lookups. -//! -//! - **Builders** (`model_builders`, `rule_builders`): code that constructs -//! problem instances and computes solutions via BruteForce/ILP. Used only -//! for regenerating fixtures and for verification tests. -//! -//! The public API (`build_*_db`, `find_*_example`) loads from fixtures. -//! Use `compute_*_db` to regenerate from code (slow, test/CI only). +//! Model specs are pure data (`Box` + optimal config + value). +//! Rule specs run `reduce_to()` (fast, no solver) with pre-stored solution pairs. use crate::error::{ProblemError, Result}; use crate::export::{ExampleDb, ModelDb, ModelExample, ProblemRef, RuleDb, RuleExample}; @@ -57,52 +51,29 @@ fn validate_model_uniqueness(models: &[ModelExample]) -> Result<()> { Ok(()) } -// ---- Fixture loading (fast, used by default) ---- - -/// Load the full example database from the embedded fixture file. +/// Build the full example database from specs. +/// +/// Fast — specs store concrete instances and pre-computed solutions, +/// no solver is called. pub fn build_example_db() -> Result { - static EXAMPLES_JSON: &str = include_str!("fixtures/examples.json"); - let db: ExampleDb = serde_json::from_str(EXAMPLES_JSON) - .map_err(|e| ProblemError::SerializationError(format!("invalid example fixture: {e}")))?; - validate_model_uniqueness(&db.models)?; - validate_rule_uniqueness(&db.rules)?; - Ok(db) -} - -/// Load the model database from the embedded fixture file. -pub fn build_model_db() -> Result { - let db = build_example_db()?; - Ok(ModelDb { models: db.models }) -} - -/// Load the rule database from the embedded fixture file. -pub fn build_rule_db() -> Result { - let db = build_example_db()?; - Ok(RuleDb { rules: db.rules }) -} - -// ---- Computation from builders (slow, for regeneration and verification) ---- - -/// Recompute the full example database from builder code. -pub fn compute_example_db() -> Result { - let model_db = compute_model_db()?; - let rule_db = compute_rule_db()?; + let model_db = build_model_db()?; + let rule_db = build_rule_db()?; Ok(ExampleDb { models: model_db.models, rules: rule_db.rules, }) } -/// Recompute the model database from builder code (runs BruteForce). -pub fn compute_model_db() -> Result { +/// Build the model database from specs. +pub fn build_model_db() -> Result { let mut models = model_builders::build_model_examples(); models.sort_by_key(model_key); validate_model_uniqueness(&models)?; Ok(ModelDb { models }) } -/// Recompute the rule database from builder code (runs BruteForce/ILP). -pub fn compute_rule_db() -> Result { +/// Build the rule database from specs. +pub fn build_rule_db() -> Result { let mut rules = rule_builders::build_rule_examples(); rules.sort_by_key(rule_key); validate_rule_uniqueness(&rules)?; diff --git a/src/example_db/model_builders.rs b/src/example_db/model_builders.rs index a866a953e..a34433901 100644 --- a/src/example_db/model_builders.rs +++ b/src/example_db/model_builders.rs @@ -1,14 +1,23 @@ use crate::export::ModelExample; pub fn build_model_examples() -> Vec { - // Graph model examples, including UndirectedTwoCommodityIntegralFlow, are - // gathered from the graph module's canonical example registry. crate::models::graph::canonical_model_example_specs() .into_iter() .chain(crate::models::formula::canonical_model_example_specs()) .chain(crate::models::set::canonical_model_example_specs()) .chain(crate::models::algebraic::canonical_model_example_specs()) .chain(crate::models::misc::canonical_model_example_specs()) - .map(|spec| (spec.build)()) + .map(|spec| { + let problem_name = spec.instance.problem_name().to_string(); + let variant = spec.instance.variant_map(); + let instance_json = spec.instance.serialize_json(); + ModelExample::new( + &problem_name, + variant, + instance_json, + spec.optimal_config, + spec.optimal_value, + ) + }) .collect() } diff --git a/src/example_db/rule_builders.rs b/src/example_db/rule_builders.rs index 741f75835..89cad2b67 100644 --- a/src/example_db/rule_builders.rs +++ b/src/example_db/rule_builders.rs @@ -6,58 +6,3 @@ pub fn build_rule_examples() -> Vec { .map(|spec| (spec.build)()) .collect() } - -#[cfg(test)] -mod tests { - #[test] - fn builds_all_canonical_rule_examples() { - let examples = crate::example_db::compute_rule_db() - .expect("compute should succeed") - .rules; - - assert!(!examples.is_empty()); - assert!(examples - .iter() - .all(|example| !example.source.problem.is_empty())); - assert!(examples - .iter() - .all(|example| !example.target.problem.is_empty())); - assert!(examples - .iter() - .all(|example| example.source.instance.is_object())); - assert!(examples - .iter() - .all(|example| example.target.instance.is_object())); - } - - #[test] - fn satisfiability_to_kcoloring_uses_full_problem_serialization() { - let specs = crate::rules::canonical_rule_example_specs(); - let spec = specs - .iter() - .find(|s| s.id == "satisfiability_to_kcoloring") - .unwrap(); - let example = (spec.build)(); - - assert_eq!(example.source.problem, "Satisfiability"); - assert_eq!(example.target.problem, "KColoring"); - assert!(example.source.instance.get("num_vars").is_some()); - assert!(example.target.instance.get("graph").is_some()); - } - - #[test] - fn factoring_to_circuitsat_contains_complete_solution_pairs() { - let specs = crate::rules::canonical_rule_example_specs(); - let spec = specs - .iter() - .find(|s| s.id == "factoring_to_circuitsat") - .unwrap(); - let example = (spec.build)(); - - assert!(!example.solutions.is_empty()); - assert!(example - .solutions - .iter() - .all(|pair| !pair.source_config.is_empty() && !pair.target_config.is_empty())); - } -} diff --git a/src/example_db/specs.rs b/src/example_db/specs.rs index 6d058a7f3..d5cb82a85 100644 --- a/src/example_db/specs.rs +++ b/src/example_db/specs.rs @@ -3,28 +3,29 @@ //! These types describe canonical model and rule examples with metadata //! that can be validated against the catalog and reduction registry. -use crate::export::{ModelExample, ProblemSide, RuleExample, SampleEval, SolutionPair}; -use crate::models::algebraic::{VariableDomain, ILP}; -use crate::prelude::{OptimizationProblem, Problem, ReduceTo, ReductionResult}; -use crate::rules::{MinimizeSteps, ReductionGraph}; -use crate::solvers::{BruteForce, ILPSolver}; -use crate::types::ProblemSize; +use crate::export::{ProblemSide, RuleExample, SolutionPair}; +use crate::prelude::{Problem, ReduceTo, ReductionResult}; +use crate::registry::DynProblem; use serde::Serialize; -use std::any::Any; -#[cfg(feature = "ilp-solver")] -use std::sync::OnceLock; /// Specification for a canonical model example. -#[allow(dead_code)] +/// +/// Stores a concrete problem instance and its known optimal solution. +/// The instance is type-erased via `DynProblem` for heterogeneous collection. +#[allow(dead_code)] // `id` field is only read in tests pub struct ModelExampleSpec { - /// Unique example identifier. + /// Unique example identifier (used by uniqueness tests). pub id: &'static str, - /// Builder function that produces the full exported example. - pub build: fn() -> ModelExample, + /// The concrete problem instance (type-erased). + pub instance: Box, + /// One known optimal configuration. + pub optimal_config: Vec, + /// The optimal value as a serializable JSON value. + pub optimal_value: serde_json::Value, } /// Specification for a canonical rule example. -#[allow(dead_code)] +#[allow(dead_code)] // `id` field is only read in tests pub struct RuleExampleSpec { /// Unique example identifier. pub id: &'static str, @@ -32,71 +33,6 @@ pub struct RuleExampleSpec { pub build: fn() -> RuleExample, } -// ---- Model example helpers ---- - -pub fn sample_eval

(problem: &P, config: Vec) -> SampleEval -where - P: Problem, - P::Metric: Serialize, -{ - let metric = - serde_json::to_value(problem.evaluate(&config)).expect("Failed to serialize metric"); - SampleEval { config, metric } -} - -pub fn optimization_example

(problem: P, samples: Vec>) -> ModelExample -where - P: OptimizationProblem + Serialize, - P::Metric: Serialize, -{ - let sample_evals = samples - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - let optimal = BruteForce::new() - .find_all_best(&problem) - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - ModelExample::from_problem(&problem, sample_evals, optimal) -} - -pub fn satisfaction_example

(problem: P, samples: Vec>) -> ModelExample -where - P: Problem + Serialize, -{ - let sample_evals = samples - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - let satisfying = BruteForce::new() - .find_all_satisfying(&problem) - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - ModelExample::from_problem(&problem, sample_evals, satisfying) -} - -pub fn explicit_example

( - problem: P, - samples: Vec>, - optimal_configs: Vec>, -) -> ModelExample -where - P: Problem + Serialize, - P::Metric: Serialize, -{ - let sample_evals = samples - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - let optimal = optimal_configs - .into_iter() - .map(|config| sample_eval(&problem, config)) - .collect(); - ModelExample::from_problem(&problem, sample_evals, optimal) -} - // ---- Rule example helpers ---- pub fn assemble_rule_example( @@ -115,171 +51,14 @@ where } } -pub fn direct_best_example(source: S, keep: Keep) -> RuleExample +/// Assemble a rule example from a source and its reduction, with a pre-stored solution pair. +pub fn rule_example_with_witness(source: S, solution: SolutionPair) -> RuleExample where S: Problem + Serialize + ReduceTo, - T: OptimizationProblem + Serialize + 'static, - T::Metric: Serialize, - Keep: Fn(&S, &[usize]) -> bool, -{ - let reduction = ReduceTo::::reduce_to(&source); - let target = reduction.target_problem(); - let solutions = choose_best_target_solution(target, |target_config| { - build_solution_pair(&source, &reduction, target_config, &keep) - }) - .into_iter() - .collect(); - assemble_rule_example(&source, target, solutions) -} - -pub fn direct_satisfying_example(source: S, keep: Keep) -> RuleExample -where - S: Problem + Serialize + ReduceTo, - T: Problem + Serialize + 'static, - Keep: Fn(&S, &[usize]) -> bool, -{ - let reduction = ReduceTo::::reduce_to(&source); - let target = reduction.target_problem(); - let solutions = choose_satisfying_target_solution(target, |target_config| { - build_solution_pair(&source, &reduction, target_config, &keep) - }) - .into_iter() - .collect(); - assemble_rule_example(&source, target, solutions) -} - -pub fn direct_ilp_example(source: S, keep: Keep) -> RuleExample -where - S: Problem + Serialize + ReduceTo>, - ILP: Serialize, - V: VariableDomain, - Keep: Fn(&S, &[usize]) -> bool, + T: Problem + Serialize, + >::Result: ReductionResult, { - let reduction = ReduceTo::>::reduce_to(&source); + let reduction = source.reduce_to(); let target = reduction.target_problem(); - let solutions = choose_best_target_solution(target, |target_config| { - build_solution_pair(&source, &reduction, target_config, &keep) - }) - .into_iter() - .collect(); - assemble_rule_example(&source, target, solutions) -} - -pub fn keep_bool_source(source: &S, config: &[usize]) -> bool -where - S: Problem, -{ - source.evaluate(config) -} - -fn choose_best_target_solution(target: &T, keep: Keep) -> Option -where - T: OptimizationProblem + 'static, - Keep: Fn(&[usize]) -> Option, -{ - choose_available_ilp_solution(target) - .as_deref() - .and_then(&keep) - .or_else(|| first_matching_solution(BruteForce::new().find_all_best(target), keep)) -} - -fn choose_satisfying_target_solution(target: &T, keep: Keep) -> Option -where - T: Problem + 'static, - Keep: Fn(&[usize]) -> Option, -{ - choose_available_ilp_solution(target) - .as_deref() - .and_then(&keep) - .or_else(|| first_matching_solution(BruteForce::new().find_all_satisfying(target), keep)) -} - -fn build_solution_pair( - source: &S, - reduction: &R, - target_config: &[usize], - keep: &Keep, -) -> Option -where - S: Problem, - R: ReductionResult, - Keep: Fn(&S, &[usize]) -> bool, -{ - let source_config = reduction.extract_solution(target_config); - keep(source, &source_config).then_some(SolutionPair { - source_config, - target_config: target_config.to_vec(), - }) -} - -fn first_matching_solution( - mut candidates: Vec>, - keep: Keep, -) -> Option -where - Keep: Fn(&[usize]) -> Option, -{ - candidates.sort(); - candidates.iter().find_map(|candidate| keep(candidate)) -} - -#[cfg(feature = "ilp-solver")] -fn choose_available_ilp_solution(problem: &T) -> Option> -where - T: Problem + 'static, -{ - let problem_any = problem as &dyn Any; - if let Some(ilp) = problem_any.downcast_ref::>() { - return ILPSolver::new().solve(ilp); - } - if let Some(ilp) = problem_any.downcast_ref::>() { - return ILPSolver::new().solve(ilp); - } - - let graph = ilp_reduction_graph(); - let source_variant = ReductionGraph::variant_to_map(&T::variant()); - let input_size = ProblemSize::new(vec![]); - - let bool_variant = ReductionGraph::variant_to_map(&ILP::::variant()); - if let Some(path) = graph.find_cheapest_path( - T::NAME, - &source_variant, - "ILP", - &bool_variant, - &input_size, - &MinimizeSteps, - ) { - let chain = graph.reduce_along_path(&path, problem as &dyn Any)?; - let ilp = chain.target_problem::>(); - let ilp_solution = ILPSolver::new().solve(ilp)?; - return Some(chain.extract_solution(&ilp_solution)); - } - - let i32_variant = ReductionGraph::variant_to_map(&ILP::::variant()); - let path = graph.find_cheapest_path( - T::NAME, - &source_variant, - "ILP", - &i32_variant, - &input_size, - &MinimizeSteps, - )?; - let chain = graph.reduce_along_path(&path, problem as &dyn Any)?; - let ilp = chain.target_problem::>(); - let ilp_solution = ILPSolver::new().solve(ilp)?; - Some(chain.extract_solution(&ilp_solution)) -} - -#[cfg(feature = "ilp-solver")] -fn ilp_reduction_graph() -> &'static ReductionGraph { - static GRAPH: OnceLock = OnceLock::new(); - GRAPH.get_or_init(ReductionGraph::new) -} - -#[cfg(not(feature = "ilp-solver"))] -fn choose_available_ilp_solution(_problem: &T) -> Option> -where - T: Problem + 'static, -{ - None + assemble_rule_example(&source, target, vec![solution]) } diff --git a/src/export.rs b/src/export.rs index a308ce075..331055caf 100644 --- a/src/export.rs +++ b/src/export.rs @@ -63,32 +63,33 @@ pub struct RuleExample { pub solutions: Vec, } -/// A complete model example: instance + evaluations. +/// A complete model example: instance + known optimal solution. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct ModelExample { pub problem: String, pub variant: BTreeMap, pub instance: serde_json::Value, - pub samples: Vec, - pub optimal: Vec, + pub optimal_config: Vec, + pub optimal_value: serde_json::Value, } impl ModelExample { - /// Build a serializable model example from a typed problem plus evaluated configs. - pub fn from_problem

(problem: &P, samples: Vec, optimal: Vec) -> Self - where - P: Problem + Serialize, - { + pub fn new( + problem: &str, + variant: BTreeMap, + instance: serde_json::Value, + optimal_config: Vec, + optimal_value: serde_json::Value, + ) -> Self { Self { - problem: P::NAME.to_string(), - variant: variant_to_map(P::variant()), - instance: serde_json::to_value(problem).expect("Failed to serialize problem instance"), - samples, - optimal, + problem: problem.to_string(), + variant, + instance, + optimal_config, + optimal_value, } } - /// Extract the structural identity of this model example. pub fn problem_ref(&self) -> ProblemRef { ProblemRef { name: self.problem.clone(), @@ -116,12 +117,6 @@ pub struct ExampleDb { pub rules: Vec, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct SampleEval { - pub config: Vec, - pub metric: serde_json::Value, -} - /// Look up `ReductionOverhead` for a direct reduction using `ReductionGraph::find_best_entry`. pub fn lookup_overhead( source_name: &str, diff --git a/src/models/algebraic/bmf.rs b/src/models/algebraic/bmf.rs index 4e91eda62..74d011a06 100644 --- a/src/models/algebraic/bmf.rs +++ b/src/models/algebraic/bmf.rs @@ -239,20 +239,16 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "bmf", - build: || { - let problem = BMF::new( - vec![ - vec![true, true, false], - vec![true, true, true], - vec![false, true, true], - ], - 2, - ); - crate::example_db::specs::optimization_example( - problem, - vec![vec![1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1]], - ) - }, + instance: Box::new(BMF::new( + vec![ + vec![true, true, false], + vec![true, true, true], + vec![false, true, true], + ], + 2, + )), + optimal_config: vec![0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0], + optimal_value: serde_json::json!({"Valid": 0}), }] } diff --git a/src/models/algebraic/closest_vector_problem.rs b/src/models/algebraic/closest_vector_problem.rs index e3595f00c..f707355a4 100644 --- a/src/models/algebraic/closest_vector_problem.rs +++ b/src/models/algebraic/closest_vector_problem.rs @@ -259,14 +259,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "closest_vector_problem_i32", - build: || { - let problem = ClosestVectorProblem::new( - vec![vec![2, 0], vec![1, 2]], - vec![2.8, 1.5], - vec![VarBounds::bounded(-2, 4), VarBounds::bounded(-2, 4)], - ); - crate::example_db::specs::optimization_example(problem, vec![vec![3, 3]]) - }, + instance: Box::new(ClosestVectorProblem::new( + vec![vec![2, 0], vec![1, 2]], + vec![2.8, 1.5], + vec![VarBounds::bounded(-2, 4), VarBounds::bounded(-2, 4)], + )), + optimal_config: vec![3, 3], + optimal_value: serde_json::json!({"Valid": 0.5385164807134505}), }] } diff --git a/src/models/algebraic/ilp.rs b/src/models/algebraic/ilp.rs index c947c82fb..5dab49674 100644 --- a/src/models/algebraic/ilp.rs +++ b/src/models/algebraic/ilp.rs @@ -283,18 +283,17 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "ilp_i32", - build: || { - let problem = ILP::::new( - 2, - vec![ - LinearConstraint::le(vec![(0, 1.0), (1, 1.0)], 5.0), - LinearConstraint::le(vec![(0, 4.0), (1, 7.0)], 28.0), - ], - vec![(0, -5.0), (1, -6.0)], - ObjectiveSense::Minimize, - ); - crate::example_db::specs::explicit_example(problem, vec![vec![0, 4]], vec![vec![3, 2]]) - }, + instance: Box::new(ILP::::new( + 2, + vec![ + LinearConstraint::le(vec![(0, 1.0), (1, 1.0)], 5.0), + LinearConstraint::le(vec![(0, 4.0), (1, 7.0)], 28.0), + ], + vec![(0, -5.0), (1, -6.0)], + ObjectiveSense::Minimize, + )), + optimal_config: vec![3, 2], + optimal_value: serde_json::json!({"Valid": -27.0}), }] } diff --git a/src/models/algebraic/qubo.rs b/src/models/algebraic/qubo.rs index 602ee1bf6..f1b76091a 100644 --- a/src/models/algebraic/qubo.rs +++ b/src/models/algebraic/qubo.rs @@ -199,14 +199,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "qubo_f64", - build: || { - let problem = QUBO::from_matrix(vec![ - vec![-1.0, 2.0, 0.0], - vec![0.0, -1.0, 2.0], - vec![0.0, 0.0, -1.0], - ]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1]]) - }, + instance: Box::new(QUBO::from_matrix(vec![ + vec![-1.0, 2.0, 0.0], + vec![0.0, -1.0, 2.0], + vec![0.0, 0.0, -1.0], + ])), + optimal_config: vec![1, 0, 1], + optimal_value: serde_json::json!({"Valid": -2.0}), }] } diff --git a/src/models/formula/circuit.rs b/src/models/formula/circuit.rs index 7279357d1..f252c18b0 100644 --- a/src/models/formula/circuit.rs +++ b/src/models/formula/circuit.rs @@ -314,26 +314,22 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "circuit_sat", - build: || { - let problem = CircuitSAT::new(Circuit::new(vec![ - Assignment::new( - vec!["a".to_string()], - BooleanExpr::and(vec![BooleanExpr::var("x1"), BooleanExpr::var("x2")]), - ), - Assignment::new( - vec!["b".to_string()], - BooleanExpr::or(vec![BooleanExpr::var("x1"), BooleanExpr::var("x2")]), - ), - Assignment::new( - vec!["c".to_string()], - BooleanExpr::xor(vec![BooleanExpr::var("a"), BooleanExpr::var("b")]), - ), - ])); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![0, 1, 1, 0, 1], vec![0, 1, 1, 1, 0]], - ) - }, + instance: Box::new(CircuitSAT::new(Circuit::new(vec![ + Assignment::new( + vec!["a".to_string()], + BooleanExpr::and(vec![BooleanExpr::var("x1"), BooleanExpr::var("x2")]), + ), + Assignment::new( + vec!["b".to_string()], + BooleanExpr::or(vec![BooleanExpr::var("x1"), BooleanExpr::var("x2")]), + ), + Assignment::new( + vec!["c".to_string()], + BooleanExpr::xor(vec![BooleanExpr::var("a"), BooleanExpr::var("b")]), + ), + ]))), + optimal_config: vec![0, 0, 0, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/formula/ksat.rs b/src/models/formula/ksat.rs index d8d7d8065..0b9681a7c 100644 --- a/src/models/formula/ksat.rs +++ b/src/models/formula/ksat.rs @@ -194,20 +194,19 @@ crate::declare_variants! { #[cfg(feature = "example-db")] pub(crate) fn canonical_model_example_specs() -> Vec { + use super::CNFClause; vec![crate::example_db::specs::ModelExampleSpec { id: "ksatisfiability_k3", - build: || { - use super::CNFClause; - let problem = KSatisfiability::::new( - 3, - vec![ - CNFClause::new(vec![1, 2, 3]), - CNFClause::new(vec![-1, -2, 3]), - CNFClause::new(vec![1, -2, -3]), - ], - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 1]]) - }, + instance: Box::new(KSatisfiability::::new( + 3, + vec![ + CNFClause::new(vec![1, 2, 3]), + CNFClause::new(vec![-1, -2, 3]), + CNFClause::new(vec![1, -2, -3]), + ], + )), + optimal_config: vec![0, 0, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/formula/sat.rs b/src/models/formula/sat.rs index 11875163e..17272080c 100644 --- a/src/models/formula/sat.rs +++ b/src/models/formula/sat.rs @@ -231,17 +231,16 @@ pub(crate) fn is_satisfying_assignment( pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "satisfiability", - build: || { - let problem = Satisfiability::new( - 3, - vec![ - CNFClause::new(vec![1, 2]), - CNFClause::new(vec![-1, 3]), - CNFClause::new(vec![-2, -3]), - ], - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 1]]) - }, + instance: Box::new(Satisfiability::new( + 3, + vec![ + CNFClause::new(vec![1, 2]), + CNFClause::new(vec![-1, 3]), + CNFClause::new(vec![-2, -3]), + ], + )), + optimal_config: vec![0, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/balanced_complete_bipartite_subgraph.rs b/src/models/graph/balanced_complete_bipartite_subgraph.rs index dd648f847..dbb46d4e5 100644 --- a/src/models/graph/balanced_complete_bipartite_subgraph.rs +++ b/src/models/graph/balanced_complete_bipartite_subgraph.rs @@ -151,34 +151,29 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "balanced_complete_bipartite_subgraph", - build: || { - let problem = BalancedCompleteBipartiteSubgraph::new( - BipartiteGraph::new( - 4, - 4, - vec![ - (0, 0), - (0, 1), - (0, 2), - (1, 0), - (1, 1), - (1, 2), - (2, 0), - (2, 1), - (2, 2), - (3, 0), - (3, 1), - (3, 3), - ], - ), - 3, - ); - - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 1, 1, 0, 1, 1, 1, 0]], - ) - }, + instance: Box::new(BalancedCompleteBipartiteSubgraph::new( + BipartiteGraph::new( + 4, + 4, + vec![ + (0, 0), + (0, 1), + (0, 2), + (1, 0), + (1, 1), + (1, 2), + (2, 0), + (2, 1), + (2, 2), + (3, 0), + (3, 1), + (3, 3), + ], + ), + 3, + )), + optimal_config: vec![1, 1, 1, 0, 1, 1, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/biclique_cover.rs b/src/models/graph/biclique_cover.rs index 8df44f6d4..ca1bf2e4a 100644 --- a/src/models/graph/biclique_cover.rs +++ b/src/models/graph/biclique_cover.rs @@ -252,19 +252,15 @@ crate::declare_variants! { #[cfg(feature = "example-db")] pub(crate) fn canonical_model_example_specs() -> Vec { + use crate::topology::BipartiteGraph; vec![crate::example_db::specs::ModelExampleSpec { id: "biclique_cover", - build: || { - use crate::topology::BipartiteGraph; - let problem = BicliqueCover::new( - BipartiteGraph::new(2, 3, vec![(0, 0), (0, 1), (1, 1), (1, 2)]), - 2, - ); - crate::example_db::specs::optimization_example( - problem, - vec![vec![1, 0, 0, 1, 1, 0, 1, 1, 0, 1]], - ) - }, + instance: Box::new(BicliqueCover::new( + BipartiteGraph::new(2, 3, vec![(0, 0), (0, 1), (1, 1), (1, 2)]), + 2, + )), + optimal_config: vec![0, 1, 0, 1, 0, 1, 0, 1, 0, 1], + optimal_value: serde_json::json!({"Valid": 5}), }] } diff --git a/src/models/graph/biconnectivity_augmentation.rs b/src/models/graph/biconnectivity_augmentation.rs index e6ebedc02..b4f2bbc59 100644 --- a/src/models/graph/biconnectivity_augmentation.rs +++ b/src/models/graph/biconnectivity_augmentation.rs @@ -267,27 +267,23 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "biconnectivity_augmentation", - build: || { - let problem = BiconnectivityAugmentation::new( - SimpleGraph::path(6), - vec![ - (0, 2, 1), - (0, 3, 2), - (0, 4, 3), - (1, 3, 1), - (1, 4, 2), - (1, 5, 3), - (2, 4, 1), - (2, 5, 2), - (3, 5, 1), - ], - 4, - ); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 0, 0, 1, 0, 0, 1, 0, 1]], - ) - }, + instance: Box::new(BiconnectivityAugmentation::new( + SimpleGraph::path(6), + vec![ + (0, 2, 1), + (0, 3, 2), + (0, 4, 3), + (1, 3, 1), + (1, 4, 2), + (1, 5, 3), + (2, 4, 1), + (2, 5, 2), + (3, 5, 1), + ], + 4, + )), + optimal_config: vec![1, 0, 0, 1, 0, 0, 1, 0, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/bounded_component_spanning_forest.rs b/src/models/graph/bounded_component_spanning_forest.rs index 3af20610f..053edbf57 100644 --- a/src/models/graph/bounded_component_spanning_forest.rs +++ b/src/models/graph/bounded_component_spanning_forest.rs @@ -211,8 +211,8 @@ where pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "bounded_component_spanning_forest_simplegraph_i32", - build: || { - let graph = SimpleGraph::new( + instance: Box::new(BoundedComponentSpanningForest::new( + SimpleGraph::new( 8, vec![ (0, 1), @@ -226,14 +226,13 @@ pub(crate) fn canonical_model_example_specs() -> Vec Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "directed_two_commodity_integral_flow", - build: || { - let graph = DirectedGraph::new( + instance: Box::new(DirectedTwoCommodityIntegralFlow::new( + DirectedGraph::new( 6, vec![ (0, 2), @@ -286,17 +286,17 @@ pub(crate) fn canonical_model_example_specs() -> Vec2->4 (arcs 0,4), commodity 2 path 1->3->5 (arcs 3,7) - // config = [f1(a0)..f1(a7), f2(a0)..f2(a7)] - // = [1,0,0,0,1,0,0,0, 0,0,0,1,0,0,0,1] - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1]], - ) - }, + ), + vec![1; 8], + 0, + 4, + 1, + 5, + 1, + 1, + )), + optimal_config: vec![1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/hamiltonian_circuit.rs b/src/models/graph/hamiltonian_circuit.rs index 49abad338..9eed25e78 100644 --- a/src/models/graph/hamiltonian_circuit.rs +++ b/src/models/graph/hamiltonian_circuit.rs @@ -146,24 +146,23 @@ impl SatisfactionProblem for HamiltonianCircuit {} pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "hamiltonian_circuit_simplegraph", - build: || { - // Prism graph (triangular prism): 6 vertices, 9 edges - let problem = HamiltonianCircuit::new(SimpleGraph::new( - 6, - vec![ - (0, 1), - (1, 2), - (2, 0), - (3, 4), - (4, 5), - (5, 3), - (0, 3), - (1, 4), - (2, 5), - ], - )); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 1, 2, 5, 4, 3]]) - }, + // Prism graph (triangular prism): 6 vertices, 9 edges + instance: Box::new(HamiltonianCircuit::new(SimpleGraph::new( + 6, + vec![ + (0, 1), + (1, 2), + (2, 0), + (3, 4), + (4, 5), + (5, 3), + (0, 3), + (1, 4), + (2, 5), + ], + ))), + optimal_config: vec![0, 1, 2, 5, 4, 3], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/hamiltonian_path.rs b/src/models/graph/hamiltonian_path.rs index 4ecc617ce..0ab9ba528 100644 --- a/src/models/graph/hamiltonian_path.rs +++ b/src/models/graph/hamiltonian_path.rs @@ -150,22 +150,21 @@ pub(crate) fn is_valid_hamiltonian_path(graph: &G, config: &[usize]) - pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "hamiltonian_path_simplegraph", - build: || { - let problem = HamiltonianPath::new(SimpleGraph::new( - 6, - vec![ - (0, 1), - (0, 2), - (1, 3), - (2, 3), - (3, 4), - (3, 5), - (4, 2), - (5, 1), - ], - )); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 2, 4, 3, 1, 5]]) - }, + instance: Box::new(HamiltonianPath::new(SimpleGraph::new( + 6, + vec![ + (0, 1), + (0, 2), + (1, 3), + (2, 3), + (3, 4), + (3, 5), + (4, 2), + (5, 1), + ], + ))), + optimal_config: vec![0, 2, 4, 3, 1, 5], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/isomorphic_spanning_tree.rs b/src/models/graph/isomorphic_spanning_tree.rs index 6f8c61c90..8e3a55075 100644 --- a/src/models/graph/isomorphic_spanning_tree.rs +++ b/src/models/graph/isomorphic_spanning_tree.rs @@ -169,12 +169,12 @@ impl SatisfactionProblem for IsomorphicSpanningTree {} pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "isomorphic_spanning_tree", - build: || { - let graph = SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); - let tree = SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3)]); - let problem = IsomorphicSpanningTree::new(graph, tree); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 1, 2, 3]]) - }, + instance: Box::new(IsomorphicSpanningTree::new( + SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]), + SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3)]), + )), + optimal_config: vec![0, 1, 2, 3], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/kcoloring.rs b/src/models/graph/kcoloring.rs index d45bb3b0f..195cbbff0 100644 --- a/src/models/graph/kcoloring.rs +++ b/src/models/graph/kcoloring.rs @@ -193,12 +193,12 @@ pub(crate) fn is_valid_coloring( pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "kcoloring_k3_simplegraph", - build: || { - use crate::topology::SimpleGraph; - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = KColoring::::new(graph); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 1, 1, 0, 2]]) - }, + instance: Box::new(KColoring::::new(SimpleGraph::new( + 5, + vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)], + ))), + optimal_config: vec![0, 1, 1, 0, 2], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/kth_best_spanning_tree.rs b/src/models/graph/kth_best_spanning_tree.rs index aa155cc6d..d65e86441 100644 --- a/src/models/graph/kth_best_spanning_tree.rs +++ b/src/models/graph/kth_best_spanning_tree.rs @@ -229,21 +229,18 @@ impl SatisfactionProblem for KthBestSpanningTree where #[cfg(feature = "example-db")] pub(crate) fn canonical_model_example_specs() -> Vec { + // K4 with weights [1,1,2,2,2,3], k=2, B=4. + // 16 spanning trees; exactly 2 have weight ≤ 4 (both weight 4): + // {01,02,03} (star at 0) and {01,02,13}. + // Satisfying configs = 2 (the two orderings of this pair). + // 12 variables → 2^12 = 4096 configs, fast to enumerate. + let graph = SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); + let problem = KthBestSpanningTree::new(graph, vec![1, 1, 2, 2, 2, 3], 2, 4); vec![crate::example_db::specs::ModelExampleSpec { id: "kth_best_spanning_tree_i32", - build: || { - // K4 with weights [1,1,2,2,2,3], k=2, B=4. - // 16 spanning trees; exactly 2 have weight ≤ 4 (both weight 4): - // {01,02,03} (star at 0) and {01,02,13}. - // Satisfying configs = 2 (the two orderings of this pair). - // 12 variables → 2^12 = 4096 configs, fast to enumerate. - let graph = SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); - let problem = KthBestSpanningTree::new(graph, vec![1, 1, 2, 2, 2, 3], 2, 4); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0], vec![0; 12]], - ) - }, + instance: Box::new(problem), + optimal_config: vec![1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/length_bounded_disjoint_paths.rs b/src/models/graph/length_bounded_disjoint_paths.rs index 46263868b..6540f11c6 100644 --- a/src/models/graph/length_bounded_disjoint_paths.rs +++ b/src/models/graph/length_bounded_disjoint_paths.rs @@ -290,31 +290,27 @@ fn encode_paths(num_vertices: usize, slots: &[&[usize]]) -> Vec { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "length_bounded_disjoint_paths_simplegraph", - build: || { - let problem = LengthBoundedDisjointPaths::new( - SimpleGraph::new( - 7, - vec![ - (0, 1), - (1, 6), - (0, 2), - (2, 3), - (3, 6), - (0, 4), - (4, 5), - (5, 6), - ], - ), - 0, - 6, - 2, - 3, - ); - crate::example_db::specs::satisfaction_example( - problem, - vec![encode_paths(7, &[&[0, 1, 6], &[0, 2, 3, 6]])], - ) - }, + instance: Box::new(LengthBoundedDisjointPaths::new( + SimpleGraph::new( + 7, + vec![ + (0, 1), + (1, 6), + (0, 2), + (2, 3), + (3, 6), + (0, 4), + (4, 5), + (5, 6), + ], + ), + 0, + 6, + 2, + 3, + )), + optimal_config: encode_paths(7, &[&[0, 1, 6], &[0, 2, 3, 6]]), + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/max_cut.rs b/src/models/graph/max_cut.rs index fdd5aa656..e3e281583 100644 --- a/src/models/graph/max_cut.rs +++ b/src/models/graph/max_cut.rs @@ -228,11 +228,12 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "max_cut_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = MaxCut::<_, i32>::unweighted(graph); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 0, 1, 0]]) - }, + instance: Box::new(MaxCut::<_, i32>::unweighted(SimpleGraph::new( + 5, + vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)], + ))), + optimal_config: vec![1, 0, 0, 1, 0], + optimal_value: serde_json::json!({"Valid": 5}), }] } diff --git a/src/models/graph/maximal_is.rs b/src/models/graph/maximal_is.rs index a2156b9f9..ac9f83add 100644 --- a/src/models/graph/maximal_is.rs +++ b/src/models/graph/maximal_is.rs @@ -193,14 +193,12 @@ where pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "maximal_is_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]); - let problem = MaximalIS::new(graph, vec![1i32; 5]); - crate::example_db::specs::optimization_example( - problem, - vec![vec![0, 1, 0, 1, 0], vec![1, 0, 1, 0, 1]], - ) - }, + instance: Box::new(MaximalIS::new( + SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]), + vec![1i32; 5], + )), + optimal_config: vec![1, 0, 1, 0, 1], + optimal_value: serde_json::json!({"Valid": 3}), }] } diff --git a/src/models/graph/maximum_clique.rs b/src/models/graph/maximum_clique.rs index d15eafc8b..8cf23de0c 100644 --- a/src/models/graph/maximum_clique.rs +++ b/src/models/graph/maximum_clique.rs @@ -184,11 +184,12 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "maximum_clique_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = MaximumClique::new(graph, vec![1i32; 5]); - crate::example_db::specs::optimization_example(problem, vec![vec![0, 0, 1, 1, 1]]) - }, + instance: Box::new(MaximumClique::new( + SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]), + vec![1i32; 5], + )), + optimal_config: vec![0, 0, 1, 1, 1], + optimal_value: serde_json::json!({"Valid": 3}), }] } diff --git a/src/models/graph/maximum_independent_set.rs b/src/models/graph/maximum_independent_set.rs index 1177398b9..5fec92078 100644 --- a/src/models/graph/maximum_independent_set.rs +++ b/src/models/graph/maximum_independent_set.rs @@ -180,9 +180,8 @@ pub(crate) fn canonical_model_example_specs() -> Vec Vec Vec Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "maximum_matching_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = MaximumMatching::<_, i32>::unit_weights(graph); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 0, 0, 1, 0]]) - }, + instance: Box::new(MaximumMatching::<_, i32>::unit_weights(SimpleGraph::new( + 5, + vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)], + ))), + optimal_config: vec![1, 0, 0, 0, 1, 0], + optimal_value: serde_json::json!({"Valid": 2}), }] } diff --git a/src/models/graph/minimum_dominating_set.rs b/src/models/graph/minimum_dominating_set.rs index 1e4b5b970..fd7c4aeb3 100644 --- a/src/models/graph/minimum_dominating_set.rs +++ b/src/models/graph/minimum_dominating_set.rs @@ -183,11 +183,12 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_dominating_set_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = MinimumDominatingSet::new(graph, vec![1i32; 5]); - crate::example_db::specs::optimization_example(problem, vec![vec![0, 0, 1, 1, 0]]) - }, + instance: Box::new(MinimumDominatingSet::new( + SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]), + vec![1i32; 5], + )), + optimal_config: vec![0, 0, 1, 1, 0], + optimal_value: serde_json::json!({"Valid": 2}), }] } diff --git a/src/models/graph/minimum_feedback_vertex_set.rs b/src/models/graph/minimum_feedback_vertex_set.rs index 6ccaa94e2..02251b45b 100644 --- a/src/models/graph/minimum_feedback_vertex_set.rs +++ b/src/models/graph/minimum_feedback_vertex_set.rs @@ -169,19 +169,18 @@ crate::declare_variants! { #[cfg(feature = "example-db")] pub(crate) fn canonical_model_example_specs() -> Vec { + use crate::topology::DirectedGraph; vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_feedback_vertex_set_i32", - build: || { - use crate::topology::DirectedGraph; - let problem = MinimumFeedbackVertexSet::new( - DirectedGraph::new( - 5, - vec![(0, 1), (1, 2), (2, 0), (0, 3), (3, 4), (4, 1), (4, 2)], - ), - vec![1i32; 5], - ); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 0, 0, 0]]) - }, + instance: Box::new(MinimumFeedbackVertexSet::new( + DirectedGraph::new( + 5, + vec![(0, 1), (1, 2), (2, 0), (0, 3), (3, 4), (4, 1), (4, 2)], + ), + vec![1i32; 5], + )), + optimal_config: vec![1, 0, 0, 0, 0], + optimal_value: serde_json::json!({"Valid": 1}), }] } diff --git a/src/models/graph/minimum_multiway_cut.rs b/src/models/graph/minimum_multiway_cut.rs index 1dd075b78..43160a340 100644 --- a/src/models/graph/minimum_multiway_cut.rs +++ b/src/models/graph/minimum_multiway_cut.rs @@ -207,13 +207,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_multiway_cut_simplegraph_i32", - build: || { - // 5 vertices, terminals {0, 2, 4}, 6 edges - let graph = SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4), (0, 4), (1, 3)]); - let problem = MinimumMultiwayCut::new(graph, vec![0, 2, 4], vec![2, 3, 1, 2, 4, 5]); - // Optimal cut: edges {(0,1), (3,4), (0,4)} = config [1,0,0,1,1,0], weight=8 - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 0, 1, 1, 0]]) - }, + instance: Box::new(MinimumMultiwayCut::new( + SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4), (0, 4), (1, 3)]), + vec![0, 2, 4], + vec![2, 3, 1, 2, 4, 5], + )), + optimal_config: vec![1, 0, 0, 1, 1, 0], + optimal_value: serde_json::json!({"Valid": 8}), }] } diff --git a/src/models/graph/minimum_sum_multicenter.rs b/src/models/graph/minimum_sum_multicenter.rs index 6d9adaca5..d8ece2554 100644 --- a/src/models/graph/minimum_sum_multicenter.rs +++ b/src/models/graph/minimum_sum_multicenter.rs @@ -267,8 +267,8 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_sum_multicenter_simplegraph_i32", - build: || { - let graph = SimpleGraph::new( + instance: Box::new(MinimumSumMulticenter::new( + SimpleGraph::new( 7, vec![ (0, 1), @@ -280,10 +280,13 @@ pub(crate) fn canonical_model_example_specs() -> Vec Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_vertex_cover_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]); - let problem = MinimumVertexCover::new(graph, vec![1i32; 5]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 0, 1, 1]]) - }, + instance: Box::new(MinimumVertexCover::new( + SimpleGraph::new(5, vec![(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]), + vec![1i32; 5], + )), + optimal_config: vec![1, 0, 0, 1, 1], + optimal_value: serde_json::json!({"Valid": 3}), }] } diff --git a/src/models/graph/multiple_choice_branching.rs b/src/models/graph/multiple_choice_branching.rs index 9887b70f0..f7252ee3d 100644 --- a/src/models/graph/multiple_choice_branching.rs +++ b/src/models/graph/multiple_choice_branching.rs @@ -304,30 +304,26 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "multiple_choice_branching_i32", - build: || { - let problem = MultipleChoiceBranching::new( - DirectedGraph::new( - 6, - vec![ - (0, 1), - (0, 2), - (1, 3), - (2, 3), - (1, 4), - (3, 5), - (4, 5), - (2, 4), - ], - ), - vec![3, 2, 4, 1, 2, 3, 1, 3], - vec![vec![0, 1], vec![2, 3], vec![4, 7], vec![5, 6]], - 10, - ); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 0, 1, 0, 0, 1, 0, 1]], - ) - }, + instance: Box::new(MultipleChoiceBranching::new( + DirectedGraph::new( + 6, + vec![ + (0, 1), + (0, 2), + (1, 3), + (2, 3), + (1, 4), + (3, 5), + (4, 5), + (2, 4), + ], + ), + vec![3, 2, 4, 1, 2, 3, 1, 3], + vec![vec![0, 1], vec![2, 3], vec![4, 7], vec![5, 6]], + 10, + )), + optimal_config: vec![1, 0, 1, 0, 0, 1, 0, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/partition_into_triangles.rs b/src/models/graph/partition_into_triangles.rs index f0356051e..717757212 100644 --- a/src/models/graph/partition_into_triangles.rs +++ b/src/models/graph/partition_into_triangles.rs @@ -164,13 +164,12 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "partition_into_triangles_simplegraph", - build: || { - let problem = PartitionIntoTriangles::new(SimpleGraph::new( - 6, - vec![(0, 1), (0, 2), (1, 2), (3, 4), (3, 5), (4, 5), (0, 3)], - )); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 0, 0, 1, 1, 1]]) - }, + instance: Box::new(PartitionIntoTriangles::new(SimpleGraph::new( + 6, + vec![(0, 1), (0, 2), (1, 2), (3, 4), (3, 5), (4, 5), (0, 3)], + ))), + optimal_config: vec![0, 0, 0, 1, 1, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/spin_glass.rs b/src/models/graph/spin_glass.rs index 1c5d9230c..92ba26c67 100644 --- a/src/models/graph/spin_glass.rs +++ b/src/models/graph/spin_glass.rs @@ -265,21 +265,20 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "spin_glass_simplegraph_i32", - build: || { - let problem = SpinGlass::::without_fields( - 5, - vec![ - ((0, 1), 1), - ((1, 2), 1), - ((3, 4), 1), - ((0, 3), 1), - ((1, 3), 1), - ((1, 4), 1), - ((2, 4), 1), - ], - ); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1, 1, 0]]) - }, + instance: Box::new(SpinGlass::::without_fields( + 5, + vec![ + ((0, 1), 1), + ((1, 2), 1), + ((3, 4), 1), + ((0, 3), 1), + ((1, 3), 1), + ((1, 4), 1), + ((2, 4), 1), + ], + )), + optimal_config: vec![1, 0, 1, 1, 0], + optimal_value: serde_json::json!({"Valid": -3}), }] } diff --git a/src/models/graph/steiner_tree.rs b/src/models/graph/steiner_tree.rs index 48e51c8d9..cb2236b78 100644 --- a/src/models/graph/steiner_tree.rs +++ b/src/models/graph/steiner_tree.rs @@ -268,14 +268,16 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "steiner_tree_simplegraph_i32", - build: || { - let graph = SimpleGraph::new( + instance: Box::new(SteinerTree::new( + SimpleGraph::new( 5, vec![(0, 1), (0, 3), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)], - ); - let problem = SteinerTree::new(graph, vec![2, 5, 2, 1, 5, 6, 1], vec![0, 2, 4]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1, 1, 0, 0, 1]]) - }, + ), + vec![2, 5, 2, 1, 5, 6, 1], + vec![0, 2, 4], + )), + optimal_config: vec![1, 0, 1, 1, 0, 0, 1], + optimal_value: serde_json::json!({"Valid": 6}), }] } diff --git a/src/models/graph/strong_connectivity_augmentation.rs b/src/models/graph/strong_connectivity_augmentation.rs index 5c67e50f1..b48d23936 100644 --- a/src/models/graph/strong_connectivity_augmentation.rs +++ b/src/models/graph/strong_connectivity_augmentation.rs @@ -228,36 +228,26 @@ where pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "strong_connectivity_augmentation_i32", - build: || { - // Path digraph 0→1→2→3→4 (not strongly connected — no back-edges). - // Nine candidate arcs are all individually affordable, but only the - // pair (4→1, w=3) + (1→0, w=5) = 8 = B achieves strong connectivity. - // Other 4-escapes (4→3, 4→2) land on vertices from which reaching 0 - // within the remaining budget is impossible. - let problem = StrongConnectivityAugmentation::new( - DirectedGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]), - vec![ - (4, 0, 10), // direct fix, too expensive - (4, 3, 3), // 4-escape to dead end - (4, 2, 3), // 4-escape to dead end - (4, 1, 3), // correct 4-escape - (3, 0, 7), // too expensive to combine - (3, 1, 3), // dead-end intermediate - (2, 0, 7), // too expensive to combine - (2, 1, 3), // dead-end intermediate - (1, 0, 5), // the closing arc - ], - 8, - ); - - crate::example_db::specs::satisfaction_example( - problem, - vec![ - vec![0, 0, 0, 1, 0, 0, 0, 0, 1], // unique: (4→1)+(1→0), w=8 - vec![0, 0, 0, 0, 0, 0, 0, 0, 0], // no arcs: not connected - ], - ) - }, + // Path digraph 0→1→2→3→4 (not strongly connected — no back-edges). + // Nine candidate arcs are all individually affordable, but only the + // pair (4→1, w=3) + (1→0, w=5) = 8 = B achieves strong connectivity. + instance: Box::new(StrongConnectivityAugmentation::new( + DirectedGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]), + vec![ + (4, 0, 10), // direct fix, too expensive + (4, 3, 3), // 4-escape to dead end + (4, 2, 3), // 4-escape to dead end + (4, 1, 3), // correct 4-escape + (3, 0, 7), // too expensive to combine + (3, 1, 3), // dead-end intermediate + (2, 0, 7), // too expensive to combine + (2, 1, 3), // dead-end intermediate + (1, 0, 5), // the closing arc + ], + 8, + )), + optimal_config: vec![0, 0, 0, 1, 0, 0, 0, 0, 1], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/graph/traveling_salesman.rs b/src/models/graph/traveling_salesman.rs index b285ba1ca..76cffc00b 100644 --- a/src/models/graph/traveling_salesman.rs +++ b/src/models/graph/traveling_salesman.rs @@ -262,11 +262,12 @@ pub(crate) fn is_hamiltonian_cycle(graph: &G, selected: &[bool]) -> bo pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "traveling_salesman_simplegraph_i32", - build: || { - let graph = SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]); - let problem = TravelingSalesman::new(graph, vec![1, 3, 2, 2, 3, 1]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1, 1, 0, 1]]) - }, + instance: Box::new(TravelingSalesman::new( + SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]), + vec![1, 3, 2, 2, 3, 1], + )), + optimal_config: vec![1, 0, 1, 1, 0, 1], + optimal_value: serde_json::json!({"Valid": 6}), }] } diff --git a/src/models/graph/undirected_two_commodity_integral_flow.rs b/src/models/graph/undirected_two_commodity_integral_flow.rs index 87aa5125d..80019a5d1 100644 --- a/src/models/graph/undirected_two_commodity_integral_flow.rs +++ b/src/models/graph/undirected_two_commodity_integral_flow.rs @@ -300,22 +300,18 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "undirected_two_commodity_integral_flow", - build: || { - let problem = UndirectedTwoCommodityIntegralFlow::new( - SimpleGraph::new(4, vec![(0, 2), (1, 2), (2, 3)]), - vec![1, 1, 2], - 0, - 3, - 1, - 3, - 1, - 1, - ); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0]], - ) - }, + instance: Box::new(UndirectedTwoCommodityIntegralFlow::new( + SimpleGraph::new(4, vec![(0, 2), (1, 2), (2, 3)]), + vec![1, 1, 2], + 0, + 3, + 1, + 3, + 1, + 1, + )), + optimal_config: vec![1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/factoring.rs b/src/models/misc/factoring.rs index 9b4a38b55..a0ebc4cb7 100644 --- a/src/models/misc/factoring.rs +++ b/src/models/misc/factoring.rs @@ -173,10 +173,9 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "factoring", - build: || { - let problem = Factoring::new(2, 3, 15); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 1, 1, 0, 1]]) - }, + instance: Box::new(Factoring::new(2, 3, 15)), + optimal_config: vec![1, 1, 1, 0, 1], + optimal_value: serde_json::json!({"Valid": 0}), }] } diff --git a/src/models/misc/longest_common_subsequence.rs b/src/models/misc/longest_common_subsequence.rs index 517891007..c84368d42 100644 --- a/src/models/misc/longest_common_subsequence.rs +++ b/src/models/misc/longest_common_subsequence.rs @@ -165,21 +165,20 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "longest_common_subsequence", - build: || { - let problem = LongestCommonSubsequence::new( - 2, - vec![ - vec![0, 1, 0, 1, 1, 0], - vec![1, 0, 0, 1, 0, 1], - vec![0, 0, 1, 0, 1, 1], - vec![1, 1, 0, 0, 1, 0], - vec![0, 1, 0, 1, 0, 1], - vec![1, 0, 1, 0, 1, 0], - ], - 3, - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 1, 0]]) - }, + instance: Box::new(LongestCommonSubsequence::new( + 2, + vec![ + vec![0, 1, 0, 1, 1, 0], + vec![1, 0, 0, 1, 0, 1], + vec![0, 0, 1, 0, 1, 1], + vec![1, 1, 0, 0, 1, 0], + vec![0, 1, 0, 1, 0, 1], + vec![1, 0, 1, 0, 1, 0], + ], + 3, + )), + optimal_config: vec![0, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/minimum_tardiness_sequencing.rs b/src/models/misc/minimum_tardiness_sequencing.rs index d33c17423..ad49f5eb0 100644 --- a/src/models/misc/minimum_tardiness_sequencing.rs +++ b/src/models/misc/minimum_tardiness_sequencing.rs @@ -194,13 +194,16 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_tardiness_sequencing", - build: || { - // 4 tasks with precedence 0 -> 2 (task 0 before task 2). - // Deadlines: task 0 by time 2, task 1 by time 3, task 2 by time 1, task 3 by time 4. - let problem = MinimumTardinessSequencing::new(4, vec![2, 3, 1, 4], vec![(0, 2)]); - // Sample config: Lehmer code [0,0,0,0] = identity permutation (schedule order 0,1,2,3) - crate::example_db::specs::optimization_example(problem, vec![vec![0, 0, 0, 0]]) - }, + // 4 tasks with precedence 0 -> 2 (task 0 before task 2). + // Deadlines: task 0 by time 2, task 1 by time 3, task 2 by time 1, task 3 by time 4. + instance: Box::new(MinimumTardinessSequencing::new( + 4, + vec![2, 3, 1, 4], + vec![(0, 2)], + )), + // Lehmer code [0,0,0,0] = identity permutation (schedule order 0,1,2,3) + optimal_config: vec![0, 0, 0, 0], + optimal_value: serde_json::json!({"Valid": 1}), }] } diff --git a/src/models/misc/multiprocessor_scheduling.rs b/src/models/misc/multiprocessor_scheduling.rs index f2f44982c..cd5d85485 100644 --- a/src/models/misc/multiprocessor_scheduling.rs +++ b/src/models/misc/multiprocessor_scheduling.rs @@ -141,14 +141,9 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "multiprocessor_scheduling", - build: || { - let problem = MultiprocessorScheduling::new(vec![4, 5, 3, 2, 6], 2, 10); - crate::example_db::specs::explicit_example( - problem, - vec![vec![0, 0, 0, 0, 0], vec![0, 1, 1, 1, 0]], - vec![vec![0, 1, 1, 1, 0]], - ) - }, + instance: Box::new(MultiprocessorScheduling::new(vec![4, 5, 3, 2, 6], 2, 10)), + optimal_config: vec![0, 1, 1, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/paintshop.rs b/src/models/misc/paintshop.rs index 495e92054..acce73f7e 100644 --- a/src/models/misc/paintshop.rs +++ b/src/models/misc/paintshop.rs @@ -200,16 +200,9 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "paintshop", - build: || { - use crate::solvers::BruteForce; - let problem = PaintShop::new(vec!["A", "B", "A", "C", "B", "C"]); - let sample = BruteForce::new() - .find_all_best(&problem) - .into_iter() - .next() - .expect("paintshop example should solve"); - crate::example_db::specs::optimization_example(problem, vec![sample]) - }, + instance: Box::new(PaintShop::new(vec!["A", "B", "A", "C", "B", "C"])), + optimal_config: vec![0, 0, 1], + optimal_value: serde_json::json!({"Valid": 2}), }] } diff --git a/src/models/misc/sequencing_with_release_times_and_deadlines.rs b/src/models/misc/sequencing_with_release_times_and_deadlines.rs index bc5a6c7b5..8a706a34f 100644 --- a/src/models/misc/sequencing_with_release_times_and_deadlines.rs +++ b/src/models/misc/sequencing_with_release_times_and_deadlines.rs @@ -158,17 +158,16 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "sequencing_with_release_times_and_deadlines", - build: || { - // 5 tasks from issue example. - // Feasible schedule order: t3, t0, t1, t2, t4 - let problem = SequencingWithReleaseTimesAndDeadlines::new( - vec![3, 2, 4, 1, 2], - vec![0, 1, 5, 0, 8], - vec![5, 6, 10, 3, 12], - ); - // Lehmer code [3,0,0,0,0] = permutation [3,0,1,2,4] - crate::example_db::specs::satisfaction_example(problem, vec![vec![3, 0, 0, 0, 0]]) - }, + // 5 tasks from issue example. + // Feasible schedule order: t3, t0, t1, t2, t4 + // Lehmer code [3,0,0,0,0] = permutation [3,0,1,2,4] + instance: Box::new(SequencingWithReleaseTimesAndDeadlines::new( + vec![3, 2, 4, 1, 2], + vec![0, 1, 5, 0, 8], + vec![5, 6, 10, 3, 12], + )), + optimal_config: vec![3, 0, 0, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/sequencing_within_intervals.rs b/src/models/misc/sequencing_within_intervals.rs index cd7c3efe4..420cb5a9b 100644 --- a/src/models/misc/sequencing_within_intervals.rs +++ b/src/models/misc/sequencing_within_intervals.rs @@ -179,21 +179,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "sequencing_within_intervals", - build: || { - use crate::solvers::BruteForce; - // Instance from the PARTITION reduction example (GJ Theorem 3.8) - let problem = SequencingWithinIntervals::new( - vec![0, 0, 0, 0, 5], - vec![11, 11, 11, 11, 6], - vec![3, 1, 2, 4, 1], - ); - let sample = BruteForce::new() - .find_all_satisfying(&problem) - .into_iter() - .next() - .expect("sequencing_within_intervals example should solve"); - crate::example_db::specs::satisfaction_example(problem, vec![sample]) - }, + instance: Box::new(SequencingWithinIntervals::new( + vec![0, 0, 0, 0, 5], + vec![11, 11, 11, 11, 6], + vec![3, 1, 2, 4, 1], + )), + optimal_config: vec![0, 6, 3, 7, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/shortest_common_supersequence.rs b/src/models/misc/shortest_common_supersequence.rs index a2c6b98db..415aef423 100644 --- a/src/models/misc/shortest_common_supersequence.rs +++ b/src/models/misc/shortest_common_supersequence.rs @@ -156,11 +156,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "shortest_common_supersequence", - build: || { - let problem = - ShortestCommonSupersequence::new(3, vec![vec![0, 1, 2], vec![1, 0, 2]], 4); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 1, 2]]) - }, + instance: Box::new(ShortestCommonSupersequence::new( + 3, + vec![vec![0, 1, 2], vec![1, 0, 2]], + 4, + )), + optimal_config: vec![0, 1, 0, 2], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/staff_scheduling.rs b/src/models/misc/staff_scheduling.rs index 60ce3b372..e2f896493 100644 --- a/src/models/misc/staff_scheduling.rs +++ b/src/models/misc/staff_scheduling.rs @@ -180,21 +180,20 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "staff_scheduling", - build: || { - let problem = StaffScheduling::new( - 5, - vec![ - vec![true, true, true, true, true, false, false], - vec![false, true, true, true, true, true, false], - vec![false, false, true, true, true, true, true], - vec![true, false, false, true, true, true, true], - vec![true, true, false, false, true, true, true], - ], - vec![2, 2, 2, 3, 3, 2, 1], - 4, - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 1, 1, 1, 0]]) - }, + instance: Box::new(StaffScheduling::new( + 5, + vec![ + vec![true, true, true, true, true, false, false], + vec![false, true, true, true, true, true, false], + vec![false, false, true, true, true, true, true], + vec![true, false, false, true, true, true, true], + vec![true, true, false, false, true, true, true], + ], + vec![2, 2, 2, 3, 3, 2, 1], + 4, + )), + optimal_config: vec![1, 1, 1, 1, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/string_to_string_correction.rs b/src/models/misc/string_to_string_correction.rs index a35af8c69..161de341c 100644 --- a/src/models/misc/string_to_string_correction.rs +++ b/src/models/misc/string_to_string_correction.rs @@ -198,19 +198,17 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "string_to_string_correction", - build: || { - let problem = - StringToStringCorrection::new(4, vec![0, 1, 2, 3, 1, 0], vec![0, 1, 3, 2, 1], 2); - // source has length 6. Domain = 2*6+1 = 13. No-op = 12. - // First operation: swap at positions 2,3 in original 6-element string. - // current_len = 6, so swap range starts at 6. - // swap_pos = value - current_len. For swap_pos=2, value = 6 + 2 = 8 - // After swap: [0,1,3,2,1,0] - // Second operation: delete at position 5 (the trailing 0). - // current_len = 6, 5 < 6 → delete index 5 - // After delete: [0,1,3,2,1] = target - crate::example_db::specs::satisfaction_example(problem, vec![vec![8, 5]]) - }, + // source has length 6. Domain = 2*6+1 = 13. No-op = 12. + // First operation: swap at positions 2,3 → value = 6 + 2 = 8 + // Second operation: delete at position 5 + instance: Box::new(StringToStringCorrection::new( + 4, + vec![0, 1, 2, 3, 1, 0], + vec![0, 1, 3, 2, 1], + 2, + )), + optimal_config: vec![8, 5], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/misc/sum_of_squares_partition.rs b/src/models/misc/sum_of_squares_partition.rs index 508efa0d2..0445d040e 100644 --- a/src/models/misc/sum_of_squares_partition.rs +++ b/src/models/misc/sum_of_squares_partition.rs @@ -192,13 +192,11 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "sum_of_squares_partition", - build: || { - // sizes=[5,3,8,2,7,1], K=3, J=240 - // Satisfying: groups {8,1},{5,2},{3,7} -> sums 9,7,10 -> 81+49+100=230 <= 240 - // Config: a0=5->group1, a1=3->group2, a2=8->group0, a3=2->group1, a4=7->group2, a5=1->group0 - let problem = SumOfSquaresPartition::new(vec![5, 3, 8, 2, 7, 1], 3, 240); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 2, 0, 1, 2, 0]]) - }, + // sizes=[5,3,8,2,7,1], K=3, J=240 + // Satisfying: groups {8,1},{5,2},{3,7} -> sums 9,7,10 -> 81+49+100=230 <= 240 + instance: Box::new(SumOfSquaresPartition::new(vec![5, 3, 8, 2, 7, 1], 3, 240)), + optimal_config: vec![1, 2, 0, 1, 2, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/set/comparative_containment.rs b/src/models/set/comparative_containment.rs index 89f11113e..50a80beb9 100644 --- a/src/models/set/comparative_containment.rs +++ b/src/models/set/comparative_containment.rs @@ -235,16 +235,15 @@ fn contains_selected_subset_unchecked(config: &[usize], set: &[usize]) -> bool { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "comparative_containment_i32", - build: || { - let problem = ComparativeContainment::with_weights( - 4, - vec![vec![0, 1, 2, 3], vec![0, 1]], - vec![vec![0, 1, 2, 3], vec![2, 3]], - vec![2, 5], - vec![3, 6], - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 0, 0]]) - }, + instance: Box::new(ComparativeContainment::with_weights( + 4, + vec![vec![0, 1, 2, 3], vec![0, 1]], + vec![vec![0, 1, 2, 3], vec![2, 3]], + vec![2, 5], + vec![3, 6], + )), + optimal_config: vec![0, 1, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/set/consecutive_sets.rs b/src/models/set/consecutive_sets.rs index 8459b3454..c787d4d56 100644 --- a/src/models/set/consecutive_sets.rs +++ b/src/models/set/consecutive_sets.rs @@ -229,15 +229,14 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "consecutive_sets", - build: || { - // YES instance from issue: w = [0, 4, 2, 5, 1, 3] - let problem = ConsecutiveSets::new( - 6, - vec![vec![0, 4], vec![2, 4], vec![2, 5], vec![1, 5], vec![1, 3]], - 6, - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![0, 4, 2, 5, 1, 3]]) - }, + // YES instance from issue: w = [0, 4, 2, 5, 1, 3] + instance: Box::new(ConsecutiveSets::new( + 6, + vec![vec![0, 4], vec![2, 4], vec![2, 5], vec![1, 5], vec![1, 3]], + 6, + )), + optimal_config: vec![0, 4, 2, 5, 1, 3], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/set/exact_cover_by_3_sets.rs b/src/models/set/exact_cover_by_3_sets.rs index f62b1701a..0bf0fdf36 100644 --- a/src/models/set/exact_cover_by_3_sets.rs +++ b/src/models/set/exact_cover_by_3_sets.rs @@ -196,21 +196,20 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "exact_cover_by_3_sets", - build: || { - let problem = ExactCoverBy3Sets::new( - 9, - vec![ - [0, 1, 2], - [0, 2, 4], - [3, 4, 5], - [3, 5, 7], - [6, 7, 8], - [1, 4, 6], - [2, 5, 8], - ], - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 0, 1, 0, 1, 0, 0]]) - }, + instance: Box::new(ExactCoverBy3Sets::new( + 9, + vec![ + [0, 1, 2], + [0, 2, 4], + [3, 4, 5], + [3, 5, 7], + [6, 7, 8], + [1, 4, 6], + [2, 5, 8], + ], + )), + optimal_config: vec![1, 0, 1, 0, 1, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/set/maximum_set_packing.rs b/src/models/set/maximum_set_packing.rs index 505073ccd..45aff086a 100644 --- a/src/models/set/maximum_set_packing.rs +++ b/src/models/set/maximum_set_packing.rs @@ -218,11 +218,14 @@ pub(crate) fn is_set_packing(sets: &[Vec], selected: &[bool]) -> bool { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "maximum_set_packing_i32", - build: || { - let problem = - MaximumSetPacking::::new(vec![vec![0, 1], vec![1, 2], vec![2, 3], vec![3, 4]]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1, 0]]) - }, + instance: Box::new(MaximumSetPacking::::new(vec![ + vec![0, 1], + vec![1, 2], + vec![2, 3], + vec![3, 4], + ])), + optimal_config: vec![0, 1, 0, 1], + optimal_value: serde_json::json!({"Valid": 2}), }] } diff --git a/src/models/set/minimum_cardinality_key.rs b/src/models/set/minimum_cardinality_key.rs index c9d6fc5b0..2ce502791 100644 --- a/src/models/set/minimum_cardinality_key.rs +++ b/src/models/set/minimum_cardinality_key.rs @@ -184,19 +184,18 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_cardinality_key", - build: || { - let problem = MinimumCardinalityKey::new( - 6, - vec![ - (vec![0, 1], vec![2]), - (vec![0, 2], vec![3]), - (vec![1, 3], vec![4]), - (vec![2, 4], vec![5]), - ], - 2, - ); - crate::example_db::specs::satisfaction_example(problem, vec![vec![1, 1, 0, 0, 0, 0]]) - }, + instance: Box::new(MinimumCardinalityKey::new( + 6, + vec![ + (vec![0, 1], vec![2]), + (vec![0, 2], vec![3]), + (vec![1, 3], vec![4]), + (vec![2, 4], vec![5]), + ], + 2, + )), + optimal_config: vec![1, 1, 0, 0, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/models/set/minimum_set_covering.rs b/src/models/set/minimum_set_covering.rs index 1c2801f25..c17eb271d 100644 --- a/src/models/set/minimum_set_covering.rs +++ b/src/models/set/minimum_set_covering.rs @@ -206,11 +206,12 @@ pub(crate) fn is_set_cover(universe_size: usize, sets: &[Vec], selected: pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "minimum_set_covering_i32", - build: || { - let problem = - MinimumSetCovering::::new(5, vec![vec![0, 1, 2], vec![1, 3], vec![2, 3, 4]]); - crate::example_db::specs::optimization_example(problem, vec![vec![1, 0, 1]]) - }, + instance: Box::new(MinimumSetCovering::::new( + 5, + vec![vec![0, 1, 2], vec![1, 3], vec![2, 3, 4]], + )), + optimal_config: vec![1, 0, 1], + optimal_value: serde_json::json!({"Valid": 2}), }] } diff --git a/src/models/set/set_basis.rs b/src/models/set/set_basis.rs index 7bde81f6f..0d0cd8dbb 100644 --- a/src/models/set/set_basis.rs +++ b/src/models/set/set_basis.rs @@ -178,17 +178,13 @@ crate::declare_variants! { pub(crate) fn canonical_model_example_specs() -> Vec { vec![crate::example_db::specs::ModelExampleSpec { id: "set_basis", - build: || { - let problem = SetBasis::new( - 4, - vec![vec![0, 1], vec![1, 2], vec![0, 2], vec![0, 1, 2]], - 3, - ); - crate::example_db::specs::satisfaction_example( - problem, - vec![vec![1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0]], - ) - }, + instance: Box::new(SetBasis::new( + 4, + vec![vec![0, 1], vec![1, 2], vec![0, 2], vec![0, 1, 2]], + 3, + )), + optimal_config: vec![0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0], + optimal_value: serde_json::json!(true), }] } diff --git a/src/registry/dyn_problem.rs b/src/registry/dyn_problem.rs index 4321a2807..6b1a9b0e0 100644 --- a/src/registry/dyn_problem.rs +++ b/src/registry/dyn_problem.rs @@ -12,6 +12,8 @@ use crate::traits::Problem; pub trait DynProblem: Any { /// Evaluate a configuration and return the result as a debug string. fn evaluate_dyn(&self, config: &[usize]) -> String; + /// Evaluate a configuration and return the result as a serializable JSON value. + fn evaluate_json(&self, config: &[usize]) -> Value; /// Serialize the problem to a JSON value. fn serialize_json(&self) -> Value; /// Downcast to `&dyn Any` for type recovery. @@ -29,12 +31,16 @@ pub trait DynProblem: Any { impl DynProblem for T where T: Problem + Serialize + 'static, - T::Metric: fmt::Debug, + T::Metric: fmt::Debug + Serialize, { fn evaluate_dyn(&self, config: &[usize]) -> String { format!("{:?}", self.evaluate(config)) } + fn evaluate_json(&self, config: &[usize]) -> Value { + serde_json::to_value(self.evaluate(config)).expect("serialize metric failed") + } + fn serialize_json(&self) -> Value { serde_json::to_value(self).expect("serialize failed") } @@ -52,10 +58,7 @@ where } fn variant_map(&self) -> BTreeMap { - T::variant() - .into_iter() - .map(|(k, v)| (k.to_string(), v.to_string())) - .collect() + crate::export::variant_to_map(T::variant()) } fn num_variables_dyn(&self) -> usize { diff --git a/src/rules/binpacking_ilp.rs b/src/rules/binpacking_ilp.rs index 6a5199c06..49dc2f51e 100644 --- a/src/rules/binpacking_ilp.rs +++ b/src/rules/binpacking_ilp.rs @@ -98,12 +98,20 @@ impl ReduceTo> for BinPacking { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "binpacking_to_ilp", build: || { - crate::example_db::specs::direct_ilp_example::<_, bool, _>( + crate::example_db::specs::rule_example_with_witness::<_, ILP>( BinPacking::new(vec![6, 5, 5, 4, 3], 10), - |_, _| true, + SolutionPair { + source_config: vec![2, 1, 0, 0, 2], + target_config: vec![ + 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + ], + }, ) }, }] diff --git a/src/rules/circuit_ilp.rs b/src/rules/circuit_ilp.rs index d6f2d7308..fcd26f97a 100644 --- a/src/rules/circuit_ilp.rs +++ b/src/rules/circuit_ilp.rs @@ -222,6 +222,7 @@ impl ReduceTo> for CircuitSAT { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::{Assignment, BooleanExpr, Circuit}; fn full_adder_circuit_sat() -> CircuitSAT { @@ -253,9 +254,15 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::< + _, + crate::models::algebraic::ILP, + >( full_adder_circuit_sat(), - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![0, 0, 0, 0, 0, 0, 0, 0], + target_config: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, ) }, }] diff --git a/src/rules/circuit_spinglass.rs b/src/rules/circuit_spinglass.rs index 16af9375c..42857d925 100644 --- a/src/rules/circuit_spinglass.rs +++ b/src/rules/circuit_spinglass.rs @@ -442,6 +442,7 @@ impl ReduceTo> for CircuitSAT { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::{Assignment, BooleanExpr, Circuit, CircuitSAT}; fn full_adder_circuit_sat() -> CircuitSAT { @@ -473,9 +474,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, SpinGlass>( full_adder_circuit_sat(), - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![0, 0, 0, 0, 0, 0, 0, 0], + target_config: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }, ) }, }] diff --git a/src/rules/coloring_ilp.rs b/src/rules/coloring_ilp.rs index cf372f89b..8fa5095c8 100644 --- a/src/rules/coloring_ilp.rs +++ b/src/rules/coloring_ilp.rs @@ -139,6 +139,7 @@ impl_kcoloring_to_ilp!(K1, K2, K3, K4); #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::topology::SimpleGraph; vec![crate::example_db::specs::RuleExampleSpec { @@ -146,9 +147,15 @@ pub(crate) fn canonical_rule_example_specs() -> Vec::with_k(SimpleGraph::new(n, edges), 3); - crate::example_db::specs::direct_ilp_example::<_, bool, _>( + crate::example_db::specs::rule_example_with_witness::<_, ILP>( source, - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![0, 2, 0, 1, 2, 1, 1, 2, 0, 0], + target_config: vec![ + 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, + ], + }, ) }, }] diff --git a/src/rules/coloring_qubo.rs b/src/rules/coloring_qubo.rs index 03613b46d..e85c498f8 100644 --- a/src/rules/coloring_qubo.rs +++ b/src/rules/coloring_qubo.rs @@ -129,6 +129,7 @@ impl_kcoloring_to_qubo!(K2, K3); #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::algebraic::QUBO; vec![crate::example_db::specs::RuleExampleSpec { @@ -136,9 +137,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec::with_k(SimpleGraph::new(n, edges), 3); - crate::example_db::specs::direct_best_example::<_, QUBO, _>( + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( source, - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![1, 2, 2, 1, 0], + target_config: vec![0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0], + }, ) }, }] diff --git a/src/rules/factoring_circuit.rs b/src/rules/factoring_circuit.rs index e4733a4e9..b000c7c8e 100644 --- a/src/rules/factoring_circuit.rs +++ b/src/rules/factoring_circuit.rs @@ -270,59 +270,21 @@ impl ReduceTo for Factoring { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { use crate::export::SolutionPair; - use crate::prelude::{ReduceTo, ReductionResult}; - use crate::solvers::BruteForce; - use std::collections::HashMap; vec![crate::example_db::specs::RuleExampleSpec { id: "factoring_to_circuitsat", build: || { - fn simulate_circuit( - circuit: &crate::models::formula::Circuit, - initial_assignments: &HashMap, - ) -> HashMap { - let mut values = initial_assignments.clone(); - for assignment in &circuit.assignments { - let result = assignment.expr.evaluate(&values); - for output in &assignment.outputs { - values.insert(output.clone(), result); - } - } - values - } - - let source = Factoring::new(3, 3, 35); - let reduction = ReduceTo::::reduce_to(&source); - let target = reduction.target_problem(); - let var_names = target.variable_names(); - let solutions = BruteForce::new() - .find_all_best(&source) - .into_iter() - .min() - .map(|source_config| { - let mut inputs: HashMap = HashMap::new(); - for (i, &bit) in source_config.iter().enumerate().take(source.m()) { - inputs.insert(format!("p{}", i + 1), bit == 1); - } - for (i, &bit) in source_config[source.m()..] - .iter() - .enumerate() - .take(source.n()) - { - inputs.insert(format!("q{}", i + 1), bit == 1); - } - let values = simulate_circuit(target.circuit(), &inputs); - let target_config = var_names - .iter() - .map(|name| usize::from(*values.get(name).unwrap_or(&false))) - .collect(); - vec![SolutionPair { - source_config, - target_config, - }] - }) - .unwrap_or_default(); - crate::example_db::specs::assemble_rule_example(&source, target, solutions) + crate::example_db::specs::rule_example_with_witness::<_, CircuitSAT>( + Factoring::new(3, 3, 35), + SolutionPair { + source_config: vec![1, 0, 1, 1, 1, 1], + target_config: vec![ + 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + ], + }, + ) }, }] } diff --git a/src/rules/factoring_ilp.rs b/src/rules/factoring_ilp.rs index 37d95d321..c66fc3f51 100644 --- a/src/rules/factoring_ilp.rs +++ b/src/rules/factoring_ilp.rs @@ -223,12 +223,19 @@ impl ReduceTo> for Factoring { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "factoring_to_ilp", build: || { - crate::example_db::specs::direct_ilp_example::<_, i32, _>( + crate::example_db::specs::rule_example_with_witness::<_, ILP>( Factoring::new(3, 3, 35), - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 1, 1, 1, 1], + target_config: vec![ + 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, + ], + }, ) }, }] diff --git a/src/rules/ilp_qubo.rs b/src/rules/ilp_qubo.rs index 44855967f..829bab31c 100644 --- a/src/rules/ilp_qubo.rs +++ b/src/rules/ilp_qubo.rs @@ -169,6 +169,7 @@ impl ReduceTo> for ILP { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::algebraic::{LinearConstraint, ObjectiveSense}; vec![crate::example_db::specs::RuleExampleSpec { @@ -187,7 +188,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( + source, + SolutionPair { + source_config: vec![1, 1, 0, 0, 1, 1], + target_config: vec![1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + }, + ) }, }] } diff --git a/src/rules/knapsack_qubo.rs b/src/rules/knapsack_qubo.rs index 1bb7a899b..fd8898ea2 100644 --- a/src/rules/knapsack_qubo.rs +++ b/src/rules/knapsack_qubo.rs @@ -100,12 +100,17 @@ impl ReduceTo> for Knapsack { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "knapsack_to_qubo", build: || { - crate::example_db::specs::direct_best_example::<_, QUBO, _>( + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( Knapsack::new(vec![2, 3, 4, 5], vec![3, 4, 5, 7], 7), - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 0, 1], + target_config: vec![1, 0, 0, 1, 0, 0, 0], + }, ) }, }] diff --git a/src/rules/ksatisfiability_qubo.rs b/src/rules/ksatisfiability_qubo.rs index e7cb2c975..a39f404c7 100644 --- a/src/rules/ksatisfiability_qubo.rs +++ b/src/rules/ksatisfiability_qubo.rs @@ -326,6 +326,7 @@ impl ReduceTo> for KSatisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::algebraic::QUBO; use crate::models::formula::CNFClause; @@ -342,9 +343,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( source, - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![0, 1, 0, 1], + target_config: vec![0, 1, 0, 1], + }, ) }, }, @@ -363,9 +367,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( source, - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![0, 0, 0, 0, 0], + target_config: vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + }, ) }, }, diff --git a/src/rules/ksatisfiability_subsetsum.rs b/src/rules/ksatisfiability_subsetsum.rs index 75e1a5a06..1f4efc32b 100644 --- a/src/rules/ksatisfiability_subsetsum.rs +++ b/src/rules/ksatisfiability_subsetsum.rs @@ -138,6 +138,7 @@ impl ReduceTo for KSatisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::CNFClause; use crate::models::misc::SubsetSum; @@ -151,9 +152,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec( + crate::example_db::specs::rule_example_with_witness::<_, SubsetSum>( source, - |_, _| true, + SolutionPair { + source_config: vec![0, 0, 1], + target_config: vec![0, 1, 0, 1, 1, 0, 1, 1, 1, 0], + }, ) }, }] diff --git a/src/rules/longestcommonsubsequence_ilp.rs b/src/rules/longestcommonsubsequence_ilp.rs index b6ecf4433..e091603ea 100644 --- a/src/rules/longestcommonsubsequence_ilp.rs +++ b/src/rules/longestcommonsubsequence_ilp.rs @@ -140,13 +140,18 @@ impl ReduceTo> for LongestCommonSubsequence { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "longestcommonsubsequence_to_ilp", build: || { let source = LongestCommonSubsequence::new(3, vec![vec![0, 1, 2], vec![1, 0, 2]], 2); - crate::example_db::specs::direct_ilp_example::<_, bool, _>( + crate::example_db::specs::rule_example_with_witness::<_, ILP>( source, - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![1, 2], + target_config: vec![0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1], + }, ) }, }] diff --git a/src/rules/maximumclique_ilp.rs b/src/rules/maximumclique_ilp.rs index 0a77d62ed..4ca25dc18 100644 --- a/src/rules/maximumclique_ilp.rs +++ b/src/rules/maximumclique_ilp.rs @@ -80,12 +80,20 @@ impl ReduceTo> for MaximumClique { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "maximumclique_to_ilp", build: || { let (n, edges) = crate::topology::small_graphs::octahedral(); let source = MaximumClique::new(SimpleGraph::new(n, edges), vec![1i32; 6]); - crate::example_db::specs::direct_ilp_example::<_, bool, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![1, 1, 1, 0, 0, 0], + target_config: vec![1, 1, 1, 0, 0, 0], + }, + ) }, }] } diff --git a/src/rules/maximumclique_maximumindependentset.rs b/src/rules/maximumclique_maximumindependentset.rs index 94d147544..38c00bcd3 100644 --- a/src/rules/maximumclique_maximumindependentset.rs +++ b/src/rules/maximumclique_maximumindependentset.rs @@ -68,6 +68,8 @@ impl ReduceTo> for MaximumClique Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "maximumclique_to_maximumindependentset", build: || { @@ -75,11 +77,16 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, - >(source, |_, _| true) + >( + source, + SolutionPair { + source_config: vec![0, 1, 1, 0], + target_config: vec![0, 1, 1, 0], + }, + ) }, }] } diff --git a/src/rules/maximumindependentset_maximumclique.rs b/src/rules/maximumindependentset_maximumclique.rs index 3cd897116..5701b3c4d 100644 --- a/src/rules/maximumindependentset_maximumclique.rs +++ b/src/rules/maximumindependentset_maximumclique.rs @@ -63,6 +63,8 @@ impl ReduceTo> for MaximumIndependentSet Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "maximumindependentset_to_maximumclique", build: || { @@ -70,9 +72,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, MaximumClique>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 1, 0, 1], + target_config: vec![1, 0, 1, 0, 1], + }, ) }, }] diff --git a/src/rules/maximumindependentset_maximumsetpacking.rs b/src/rules/maximumindependentset_maximumsetpacking.rs index 9ca2bb90a..fbe156436 100644 --- a/src/rules/maximumindependentset_maximumsetpacking.rs +++ b/src/rules/maximumindependentset_maximumsetpacking.rs @@ -123,15 +123,20 @@ impl_sp_to_is!(One); #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![ crate::example_db::specs::RuleExampleSpec { id: "maximumindependentset_to_maximumsetpacking", build: || { let (n, edges) = crate::topology::small_graphs::petersen(); let source = MaximumIndependentSet::new(SimpleGraph::new(n, edges), vec![1i32; 10]); - crate::example_db::specs::direct_best_example::<_, MaximumSetPacking, _>( + crate::example_db::specs::rule_example_with_witness::<_, MaximumSetPacking>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + target_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + }, ) }, }, @@ -140,9 +145,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, MaximumSetPacking>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + target_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + }, ) }, }, @@ -157,11 +165,16 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, - >(source, |_, _| true) + >( + source, + SolutionPair { + source_config: vec![1, 0, 0, 0, 1], + target_config: vec![1, 0, 0, 0, 1], + }, + ) }, }, crate::example_db::specs::RuleExampleSpec { @@ -175,11 +188,16 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, - >(source, |_, _| true) + >( + source, + SolutionPair { + source_config: vec![1, 0, 0, 0, 1], + target_config: vec![1, 0, 0, 0, 1], + }, + ) }, }, ] diff --git a/src/rules/maximummatching_ilp.rs b/src/rules/maximummatching_ilp.rs index 54211b499..a491bd688 100644 --- a/src/rules/maximummatching_ilp.rs +++ b/src/rules/maximummatching_ilp.rs @@ -80,12 +80,20 @@ impl ReduceTo> for MaximumMatching { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "maximummatching_to_ilp", build: || { let (n, edges) = crate::topology::small_graphs::petersen(); let source = MaximumMatching::unit_weights(SimpleGraph::new(n, edges)); - crate::example_db::specs::direct_ilp_example::<_, bool, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + target_config: vec![0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + }, + ) }, }] } diff --git a/src/rules/maximummatching_maximumsetpacking.rs b/src/rules/maximummatching_maximumsetpacking.rs index a4b984bb7..9c74bf411 100644 --- a/src/rules/maximummatching_maximumsetpacking.rs +++ b/src/rules/maximummatching_maximumsetpacking.rs @@ -64,6 +64,7 @@ impl ReduceTo> for MaximumMatching { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::set::MaximumSetPacking; vec![crate::example_db::specs::RuleExampleSpec { @@ -71,9 +72,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, MaximumSetPacking>( source, - |_, _| true, + SolutionPair { + source_config: vec![0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + target_config: vec![0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1], + }, ) }, }] diff --git a/src/rules/maximumsetpacking_ilp.rs b/src/rules/maximumsetpacking_ilp.rs index 579be7589..5a50afd45 100644 --- a/src/rules/maximumsetpacking_ilp.rs +++ b/src/rules/maximumsetpacking_ilp.rs @@ -79,6 +79,8 @@ impl ReduceTo> for MaximumSetPacking { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "maximumsetpacking_to_ilp", build: || { @@ -90,7 +92,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![0, 0, 0, 1, 1, 0], + target_config: vec![0, 0, 0, 1, 1, 0], + }, + ) }, }] } diff --git a/src/rules/maximumsetpacking_qubo.rs b/src/rules/maximumsetpacking_qubo.rs index 29c30f742..a3b13949c 100644 --- a/src/rules/maximumsetpacking_qubo.rs +++ b/src/rules/maximumsetpacking_qubo.rs @@ -63,6 +63,7 @@ impl ReduceTo> for MaximumSetPacking { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::set::MaximumSetPacking; vec![crate::example_db::specs::RuleExampleSpec { @@ -76,7 +77,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( + source, + SolutionPair { + source_config: vec![0, 0, 0, 1, 1, 0], + target_config: vec![0, 0, 0, 1, 1, 0], + }, + ) }, }] } diff --git a/src/rules/minimumdominatingset_ilp.rs b/src/rules/minimumdominatingset_ilp.rs index 3f71767f5..7725779d2 100644 --- a/src/rules/minimumdominatingset_ilp.rs +++ b/src/rules/minimumdominatingset_ilp.rs @@ -82,12 +82,20 @@ impl ReduceTo> for MinimumDominatingSet { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "minimumdominatingset_to_ilp", build: || { let (n, edges) = crate::topology::small_graphs::petersen(); let source = MinimumDominatingSet::new(SimpleGraph::new(n, edges), vec![1i32; 10]); - crate::example_db::specs::direct_ilp_example::<_, bool, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![0, 0, 1, 0, 0, 1, 0, 0, 0, 1], + target_config: vec![0, 0, 1, 0, 0, 1, 0, 0, 0, 1], + }, + ) }, }] } diff --git a/src/rules/minimumfeedbackvertexset_ilp.rs b/src/rules/minimumfeedbackvertexset_ilp.rs index d4c54cd07..82f71f94f 100644 --- a/src/rules/minimumfeedbackvertexset_ilp.rs +++ b/src/rules/minimumfeedbackvertexset_ilp.rs @@ -106,14 +106,22 @@ impl ReduceTo> for MinimumFeedbackVertexSet { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::topology::DirectedGraph; + vec![crate::example_db::specs::RuleExampleSpec { id: "minimumfeedbackvertexset_to_ilp", build: || { // Simple cycle: 0 -> 1 -> 2 -> 0 (FVS = 1 vertex) let graph = DirectedGraph::new(3, vec![(0, 1), (1, 2), (2, 0)]); let source = MinimumFeedbackVertexSet::new(graph, vec![1i32; 3]); - crate::example_db::specs::direct_ilp_example::<_, i32, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![0, 1, 0], + target_config: vec![0, 1, 0, 1, 0, 0], + }, + ) }, }] } diff --git a/src/rules/minimummultiwaycut_ilp.rs b/src/rules/minimummultiwaycut_ilp.rs index 211ce2344..143f7035a 100644 --- a/src/rules/minimummultiwaycut_ilp.rs +++ b/src/rules/minimummultiwaycut_ilp.rs @@ -129,12 +129,22 @@ impl ReduceTo> for MinimumMultiwayCut { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "minimummultiwaycut_to_ilp", build: || { let graph = SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4), (0, 4), (1, 3)]); let problem = MinimumMultiwayCut::new(graph, vec![0, 2, 4], vec![2, 3, 1, 2, 4, 5]); - crate::example_db::specs::direct_ilp_example::<_, bool, _>(problem, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + problem, + SolutionPair { + source_config: vec![1, 0, 0, 1, 1, 0], + target_config: vec![ + 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, + ], + }, + ) }, }] } diff --git a/src/rules/minimumsetcovering_ilp.rs b/src/rules/minimumsetcovering_ilp.rs index 104707772..cd0760aec 100644 --- a/src/rules/minimumsetcovering_ilp.rs +++ b/src/rules/minimumsetcovering_ilp.rs @@ -83,6 +83,8 @@ impl ReduceTo> for MinimumSetCovering { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "minimumsetcovering_to_ilp", build: || { @@ -97,7 +99,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![0, 1, 0, 1, 1, 0], + target_config: vec![0, 1, 0, 1, 1, 0], + }, + ) }, }] } diff --git a/src/rules/minimumvertexcover_maximumindependentset.rs b/src/rules/minimumvertexcover_maximumindependentset.rs index f238e3984..85a650286 100644 --- a/src/rules/minimumvertexcover_maximumindependentset.rs +++ b/src/rules/minimumvertexcover_maximumindependentset.rs @@ -93,6 +93,8 @@ impl ReduceTo> for MinimumVertexCover Vec { + use crate::export::SolutionPair; + fn vc_petersen() -> MinimumVertexCover { let (n, edges) = crate::topology::small_graphs::petersen(); MinimumVertexCover::new(SimpleGraph::new(n, edges), vec![1i32; 10]) @@ -107,21 +109,31 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, - >(mis_petersen(), |_, _| true) + >( + mis_petersen(), + SolutionPair { + source_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + target_config: vec![0, 1, 1, 0, 1, 1, 0, 0, 1, 1], + }, + ) }, }, crate::example_db::specs::RuleExampleSpec { id: "minimumvertexcover_to_maximumindependentset", build: || { - crate::example_db::specs::direct_best_example::< + crate::example_db::specs::rule_example_with_witness::< _, MaximumIndependentSet, - _, - >(vc_petersen(), |_, _| true) + >( + vc_petersen(), + SolutionPair { + source_config: vec![0, 1, 1, 0, 1, 1, 0, 0, 1, 1], + target_config: vec![1, 0, 0, 1, 0, 0, 1, 1, 0, 0], + }, + ) }, }, ] diff --git a/src/rules/minimumvertexcover_minimumsetcovering.rs b/src/rules/minimumvertexcover_minimumsetcovering.rs index 121adcebc..c15f5f8c0 100644 --- a/src/rules/minimumvertexcover_minimumsetcovering.rs +++ b/src/rules/minimumvertexcover_minimumsetcovering.rs @@ -69,14 +69,19 @@ impl ReduceTo> for MinimumVertexCover #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "minimumvertexcover_to_minimumsetcovering", build: || { let (n, edges) = crate::topology::small_graphs::petersen(); let source = MinimumVertexCover::new(SimpleGraph::new(n, edges), vec![1i32; 10]); - crate::example_db::specs::direct_best_example::<_, MinimumSetCovering, _>( + crate::example_db::specs::rule_example_with_witness::<_, MinimumSetCovering>( source, - |_, _| true, + SolutionPair { + source_config: vec![0, 1, 1, 0, 1, 1, 0, 0, 1, 1], + target_config: vec![0, 1, 1, 0, 1, 1, 0, 0, 1, 1], + }, ) }, }] diff --git a/src/rules/qubo_ilp.rs b/src/rules/qubo_ilp.rs index b4669d5a5..2410ad2ac 100644 --- a/src/rules/qubo_ilp.rs +++ b/src/rules/qubo_ilp.rs @@ -101,6 +101,8 @@ impl ReduceTo> for QUBO { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "qubo_to_ilp", build: || { @@ -113,7 +115,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![1, 1, 1, 1], + target_config: vec![1, 1, 1, 1, 1, 1, 1], + }, + ) }, }] } diff --git a/src/rules/sat_circuitsat.rs b/src/rules/sat_circuitsat.rs index cbb32bebd..7b93744ac 100644 --- a/src/rules/sat_circuitsat.rs +++ b/src/rules/sat_circuitsat.rs @@ -119,6 +119,7 @@ impl ReduceTo for Satisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::CNFClause; vec![crate::example_db::specs::RuleExampleSpec { @@ -132,9 +133,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec( + crate::example_db::specs::rule_example_with_witness::<_, CircuitSAT>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 1, 1], + target_config: vec![1, 1, 1, 1, 1, 1, 1], + }, ) }, }] diff --git a/src/rules/sat_coloring.rs b/src/rules/sat_coloring.rs index 421101d82..5426f57b2 100644 --- a/src/rules/sat_coloring.rs +++ b/src/rules/sat_coloring.rs @@ -325,6 +325,7 @@ impl ReduceTo> for Satisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::{CNFClause, Satisfiability}; vec![crate::example_db::specs::RuleExampleSpec { @@ -338,9 +339,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, KColoring>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 1, 0, 1, 1], + target_config: vec![2, 1, 0, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1], + }, ) }, }] diff --git a/src/rules/sat_ksat.rs b/src/rules/sat_ksat.rs index cfc12c46d..39be989d5 100644 --- a/src/rules/sat_ksat.rs +++ b/src/rules/sat_ksat.rs @@ -220,6 +220,7 @@ impl ReduceTo for KSatisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::CNFClause; vec![ @@ -237,9 +238,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, KSatisfiability>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 1, 1, 0, 1], + target_config: vec![1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1], + }, ) }, }, @@ -254,9 +258,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec( + crate::example_db::specs::rule_example_with_witness::<_, Satisfiability>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 1, 1, 0], + target_config: vec![1, 1, 1, 0], + }, ) }, }, diff --git a/src/rules/sat_maximumindependentset.rs b/src/rules/sat_maximumindependentset.rs index a92ebbc0d..b49367747 100644 --- a/src/rules/sat_maximumindependentset.rs +++ b/src/rules/sat_maximumindependentset.rs @@ -168,6 +168,7 @@ impl ReduceTo> for Satisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::CNFClause; fn sat_seven_clause_example() -> Satisfiability { @@ -188,13 +189,17 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, >( sat_seven_clause_example(), - crate::example_db::specs::keep_bool_source, + SolutionPair { + source_config: vec![1, 1, 1, 1, 0], + target_config: vec![ + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + ], + }, ) }, }] diff --git a/src/rules/sat_minimumdominatingset.rs b/src/rules/sat_minimumdominatingset.rs index 80323961f..e5046ac42 100644 --- a/src/rules/sat_minimumdominatingset.rs +++ b/src/rules/sat_minimumdominatingset.rs @@ -177,6 +177,7 @@ impl ReduceTo> for Satisfiability { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::formula::CNFClause; vec![crate::example_db::specs::RuleExampleSpec { @@ -194,11 +195,18 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, - _, - >(source, crate::example_db::specs::keep_bool_source) + >( + source, + SolutionPair { + source_config: vec![1, 0, 1, 1, 1], + target_config: vec![ + 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, + ) }, }] } diff --git a/src/rules/spinglass_maxcut.rs b/src/rules/spinglass_maxcut.rs index 40a146c44..e056be62c 100644 --- a/src/rules/spinglass_maxcut.rs +++ b/src/rules/spinglass_maxcut.rs @@ -181,15 +181,20 @@ impl ReduceTo> for SpinGlass { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![ crate::example_db::specs::RuleExampleSpec { id: "maxcut_to_spinglass", build: || { let (n, edges) = crate::topology::small_graphs::petersen(); let source = MaxCut::unweighted(SimpleGraph::new(n, edges)); - crate::example_db::specs::direct_best_example::<_, SpinGlass, _>( + crate::example_db::specs::rule_example_with_witness::<_, SpinGlass>( source, - |_, _| true, + SolutionPair { + source_config: vec![0, 1, 0, 1, 0, 1, 0, 0, 0, 1], + target_config: vec![0, 1, 0, 1, 0, 1, 0, 0, 0, 1], + }, ) }, }, @@ -203,9 +208,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, MaxCut>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + target_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + }, ) }, }, diff --git a/src/rules/spinglass_qubo.rs b/src/rules/spinglass_qubo.rs index df1d6cedd..41a670331 100644 --- a/src/rules/spinglass_qubo.rs +++ b/src/rules/spinglass_qubo.rs @@ -148,6 +148,8 @@ impl ReduceTo> for SpinGlass { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![ crate::example_db::specs::RuleExampleSpec { id: "qubo_to_spinglass", @@ -162,9 +164,12 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>( + crate::example_db::specs::rule_example_with_witness::<_, SpinGlass>( source, - |_, _| true, + SolutionPair { + source_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + target_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + }, ) }, }, @@ -178,9 +183,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>(source, |_, _| { - true - }) + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( + source, + SolutionPair { + source_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + target_config: vec![1, 0, 1, 1, 1, 0, 1, 0, 0, 1], + }, + ) }, }, ] diff --git a/src/rules/travelingsalesman_ilp.rs b/src/rules/travelingsalesman_ilp.rs index 6c9126a71..98a16fedb 100644 --- a/src/rules/travelingsalesman_ilp.rs +++ b/src/rules/travelingsalesman_ilp.rs @@ -198,6 +198,8 @@ impl ReduceTo> for TravelingSalesman { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; + vec![crate::example_db::specs::RuleExampleSpec { id: "travelingsalesman_to_ilp", build: || { @@ -205,7 +207,17 @@ pub(crate) fn canonical_rule_example_specs() -> Vec(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, ILP>( + source, + SolutionPair { + source_config: vec![1, 1, 0, 0, 1, 1], + target_config: vec![ + 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, + ], + }, + ) }, }] } diff --git a/src/rules/travelingsalesman_qubo.rs b/src/rules/travelingsalesman_qubo.rs index 55a83889c..89b0312ac 100644 --- a/src/rules/travelingsalesman_qubo.rs +++ b/src/rules/travelingsalesman_qubo.rs @@ -164,6 +164,7 @@ impl ReduceTo> for TravelingSalesman { #[cfg(feature = "example-db")] pub(crate) fn canonical_rule_example_specs() -> Vec { + use crate::export::SolutionPair; use crate::models::algebraic::QUBO; vec![crate::example_db::specs::RuleExampleSpec { @@ -173,7 +174,13 @@ pub(crate) fn canonical_rule_example_specs() -> Vec, _>(source, |_, _| true) + crate::example_db::specs::rule_example_with_witness::<_, QUBO>( + source, + SolutionPair { + source_config: vec![1, 1, 1], + target_config: vec![0, 0, 1, 1, 0, 0, 0, 1, 0], + }, + ) }, }] } diff --git a/src/solvers/ilp/solver.rs b/src/solvers/ilp/solver.rs index 42f832924..c7fa333c2 100644 --- a/src/solvers/ilp/solver.rs +++ b/src/solvers/ilp/solver.rs @@ -170,6 +170,64 @@ impl ILPSolver { let ilp_solution = self.solve(reduction.target_problem())?; Some(reduction.extract_solution(&ilp_solution)) } + + /// Solve a type-erased ILP instance (`ILP` or `ILP`). + /// + /// Returns `None` if the input is not an ILP type or if the solver finds no solution. + pub fn solve_dyn(&self, any: &dyn std::any::Any) -> Option> { + if let Some(ilp) = any.downcast_ref::>() { + return self.solve(ilp); + } + if let Some(ilp) = any.downcast_ref::>() { + return self.solve(ilp); + } + None + } + + /// Solve a type-erased problem by finding a reduction path to ILP. + /// + /// Tries all ILP variants, picks the cheapest path, reduces, solves, + /// and extracts the solution back. Falls back to direct ILP solve if + /// the problem is already an ILP type. + /// + /// Returns `None` if no path to ILP exists or the solver finds no solution. + pub fn solve_via_reduction( + &self, + name: &str, + variant: &std::collections::BTreeMap, + instance: &dyn std::any::Any, + ) -> Option> { + // Direct ILP solve if the problem is already ILP + if let Some(config) = self.solve_dyn(instance) { + return Some(config); + } + + use crate::rules::{MinimizeSteps, ReductionGraph}; + use crate::types::ProblemSize; + + let graph = ReductionGraph::new(); + let ilp_variants = graph.variants_for("ILP"); + let input_size = ProblemSize::new(vec![]); + + let mut best_path = None; + for dv in &ilp_variants { + if let Some(path) = + graph.find_cheapest_path(name, variant, "ILP", dv, &input_size, &MinimizeSteps) + { + let is_better = best_path + .as_ref() + .is_none_or(|current: &crate::rules::ReductionPath| path.len() < current.len()); + if is_better { + best_path = Some(path); + } + } + } + + let path = best_path?; + let chain = graph.reduce_along_path(&path, instance)?; + let ilp_solution = self.solve_dyn(chain.target_problem_any())?; + Some(chain.extract_solution(&ilp_solution)) + } } #[cfg(test)] diff --git a/src/topology/directed_graph.rs b/src/topology/directed_graph.rs index 3e136146f..d8491206a 100644 --- a/src/topology/directed_graph.rs +++ b/src/topology/directed_graph.rs @@ -36,7 +36,7 @@ use serde::{Deserialize, Serialize}; /// let cyclic = DirectedGraph::new(3, vec![(0, 1), (1, 2), (2, 0)]); /// assert!(!cyclic.is_dag()); /// ``` -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct DirectedGraph { inner: DiGraph<(), ()>, } @@ -244,6 +244,29 @@ impl PartialEq for DirectedGraph { impl Eq for DirectedGraph {} +impl Serialize for DirectedGraph { + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeStruct; + let mut state = serializer.serialize_struct("DirectedGraph", 2)?; + state.serialize_field("num_vertices", &self.num_vertices())?; + let arcs: Vec<(usize, usize)> = self.arcs(); + state.serialize_field("arcs", &arcs)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for DirectedGraph { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct GraphData { + num_vertices: usize, + arcs: Vec<(usize, usize)>, + } + let data = GraphData::deserialize(deserializer)?; + Ok(DirectedGraph::new(data.num_vertices, data.arcs)) + } +} + use crate::impl_variant_param; impl_variant_param!(DirectedGraph, "graph"); diff --git a/src/topology/graph.rs b/src/topology/graph.rs index a51cb8c2b..12e8362d8 100644 --- a/src/topology/graph.rs +++ b/src/topology/graph.rs @@ -117,7 +117,7 @@ impl GraphCast for G { /// assert!(graph.has_edge(0, 1)); /// assert!(!graph.has_edge(0, 2)); /// ``` -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] pub struct SimpleGraph { inner: UnGraph<(), ()>, } @@ -278,6 +278,29 @@ impl PartialEq for SimpleGraph { impl Eq for SimpleGraph {} +impl Serialize for SimpleGraph { + fn serialize(&self, serializer: S) -> Result { + use serde::ser::SerializeStruct; + let mut state = serializer.serialize_struct("SimpleGraph", 2)?; + state.serialize_field("num_vertices", &self.num_vertices())?; + let edges: Vec<(usize, usize)> = self.edges(); + state.serialize_field("edges", &edges)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for SimpleGraph { + fn deserialize>(deserializer: D) -> Result { + #[derive(Deserialize)] + struct GraphData { + num_vertices: usize, + edges: Vec<(usize, usize)>, + } + let data = GraphData::deserialize(deserializer)?; + Ok(SimpleGraph::new(data.num_vertices, data.edges)) + } +} + use crate::impl_variant_param; impl_variant_param!(SimpleGraph, "graph"); diff --git a/src/unit_tests/example_db.rs b/src/unit_tests/example_db.rs index 9314ed985..c42f22bac 100644 --- a/src/unit_tests/example_db.rs +++ b/src/unit_tests/example_db.rs @@ -1,14 +1,9 @@ use crate::example_db::{ - build_example_db, build_model_db, build_rule_db, compute_model_db, compute_rule_db, - find_model_example, find_rule_example, + build_example_db, build_model_db, build_rule_db, find_model_example, find_rule_example, }; use crate::export::ProblemRef; -use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP, QUBO}; -use crate::models::graph::{MaximumMatching, SpinGlass}; use crate::registry::load_dyn; use crate::rules::{registry::reduction_entries, ReductionGraph}; -use crate::topology::SimpleGraph; -use serde_json::Value; use std::collections::{BTreeMap, BTreeSet, HashSet}; #[test] @@ -45,7 +40,7 @@ fn test_find_model_example_mis_simplegraph_i32() { assert_eq!(example.variant, problem.variant); assert!(example.instance.is_object()); assert!( - !example.optimal.is_empty(), + !example.optimal_config.is_empty(), "canonical example should include optima" ); } @@ -62,7 +57,7 @@ fn test_find_model_example_exact_cover_by_3_sets() { assert_eq!(example.variant, problem.variant); assert!(example.instance.is_object()); assert!( - !example.optimal.is_empty(), + !example.optimal_config.is_empty(), "canonical example should include satisfying assignments" ); } @@ -80,7 +75,7 @@ fn test_find_model_example_staff_scheduling() { assert_eq!(example.instance["num_workers"], 4); assert!(example.instance["schedules"].is_array()); assert!( - !example.optimal.is_empty(), + !example.optimal_config.is_empty(), "canonical example should include satisfying assignments" ); } @@ -97,7 +92,7 @@ fn test_find_model_example_multiprocessor_scheduling() { assert_eq!(example.variant, problem.variant); assert!(example.instance.is_object()); assert!( - !example.optimal.is_empty(), + !example.optimal_config.is_empty(), "canonical example should include satisfying assignments" ); } @@ -114,7 +109,7 @@ fn test_find_model_example_strong_connectivity_augmentation() { assert_eq!(example.variant, problem.variant); assert!(example.instance.is_object()); assert!( - !example.optimal.is_empty(), + !example.optimal_config.is_empty(), "canonical example should include satisfying assignments" ); } @@ -219,12 +214,6 @@ fn test_build_model_db_has_unique_structural_keys() { } } -#[test] -fn test_build_rule_db_nonempty() { - let db = build_rule_db().expect("rule db should build"); - assert!(!db.rules.is_empty(), "rule db should not be empty"); -} - #[test] fn test_rule_examples_store_single_solution_pair() { let db = build_rule_db().expect("rule db should build"); @@ -241,28 +230,6 @@ fn test_rule_examples_store_single_solution_pair() { } } -#[test] -fn test_computed_rule_examples_store_single_solution_pair() { - let db = compute_rule_db().expect("computed rule db should build"); - for rule in &db.rules { - assert_eq!( - rule.solutions.len(), - 1, - "computed canonical rule example should store one witness pair for {} {:?} -> {} {:?}", - rule.source.problem, - rule.source.variant, - rule.target.problem, - rule.target.variant - ); - } -} - -#[test] -fn test_build_model_db_nonempty() { - let db = build_model_db().expect("model db should build"); - assert!(!db.models.is_empty(), "model db should not be empty"); -} - #[test] fn canonical_model_example_ids_are_unique() { let specs = crate::models::graph::canonical_model_example_specs(); @@ -298,7 +265,7 @@ fn canonical_rule_example_ids_are_unique() { #[test] fn canonical_rule_examples_cover_exactly_authored_direct_reductions() { - let computed = compute_rule_db().expect("computed rule db should build"); + let computed = build_rule_db().expect("computed rule db should build"); let example_keys: BTreeSet<_> = computed .rules .iter() @@ -364,422 +331,175 @@ fn find_model_example_nonexistent_returns_error() { ); } -fn problem_json_key(value: &Value) -> String { - serde_json::to_string(value).expect("json value should serialize") -} - -fn edge_key(edge: &Value) -> (u64, u64, String) { - let values = edge - .as_array() - .expect("graph edge should serialize as a JSON array"); - let u = values.first().and_then(Value::as_u64).unwrap_or(u64::MAX); - let v = values.get(1).and_then(Value::as_u64).unwrap_or(u64::MAX); - (u, v, problem_json_key(edge)) -} - -fn term_key(term: &Value) -> (u64, String) { - let values = term - .as_array() - .expect("ILP term should serialize as a JSON array"); - let variable = values.first().and_then(Value::as_u64).unwrap_or(u64::MAX); - (variable, problem_json_key(term)) -} - -fn graph_edges_mut(object: &mut serde_json::Map) -> Option<&mut Vec> { - let graph = object.get_mut("graph")?.as_object_mut()?; - if graph.contains_key("inner") { - return graph - .get_mut("inner")? - .as_object_mut()? - .get_mut("edges")? - .as_array_mut(); - } - graph.get_mut("edges")?.as_array_mut() -} - -fn reorder_array(values: &mut Vec, old_indices: &[usize]) { - let reordered: Vec = old_indices.iter().map(|&idx| values[idx].clone()).collect(); - *values = reordered; -} - -fn edge_aligned_fields(problem_name: &str) -> &'static [&'static str] { - match problem_name { - "MaximumMatching" | "MaxCut" | "TravelingSalesman" => &["edge_weights"], - "SpinGlass" => &["couplings"], - _ => &[], - } -} - -fn normalize_graph_instance(problem_name: &str, instance: &mut Value) { - let Some(object) = instance.as_object_mut() else { - return; - }; - let edge_order = { - let Some(edges) = graph_edges_mut(object) else { - return; - }; - let mut indexed_edges: Vec<(usize, Value)> = edges.iter().cloned().enumerate().collect(); - indexed_edges.sort_by_key(|(_, edge)| edge_key(edge)); - *edges = indexed_edges.iter().map(|(_, edge)| edge.clone()).collect(); - indexed_edges - .into_iter() - .map(|(old_index, _)| old_index) - .collect::>() - }; - - for field in edge_aligned_fields(problem_name) { - if let Some(values) = object.get_mut(*field).and_then(Value::as_array_mut) { - assert_eq!( - values.len(), - edge_order.len(), - "{problem_name}.{field} should stay aligned with graph edges", - ); - reorder_array(values, &edge_order); - } - } -} - -fn normalize_ilp_instance(instance: &mut Value) { - let Some(object) = instance.as_object_mut() else { - return; - }; - - if let Some(objective) = object.get_mut("objective").and_then(Value::as_array_mut) { - objective.sort_by_key(term_key); - } - - if let Some(constraints) = object.get_mut("constraints").and_then(Value::as_array_mut) { - for constraint in constraints.iter_mut() { - if let Some(terms) = constraint.get_mut("terms").and_then(Value::as_array_mut) { - terms.sort_by_key(term_key); - } - } - constraints.sort_by_key(problem_json_key); - } -} - -fn normalize_problem_instance(problem: &ProblemRef, instance: &Value) -> Value { - let loaded = - load_dyn(&problem.name, &problem.variant, instance.clone()).unwrap_or_else(|err| { - panic!( - "fixture instance should deserialize for {} {:?}: {}", - problem.name, problem.variant, err - ) - }); - let mut normalized = loaded.serialize_json(); - normalize_graph_instance(&problem.name, &mut normalized); - if problem.name == "ILP" { - normalize_ilp_instance(&mut normalized); - } - normalized -} - -fn numbers_semantically_equal(left: &serde_json::Number, right: &serde_json::Number) -> bool { - match (left.as_i64(), right.as_i64(), left.as_u64(), right.as_u64()) { - (Some(a), Some(b), _, _) => a == b, - (_, _, Some(a), Some(b)) => a == b, - _ => { - let Some(left) = left.as_f64() else { - return false; - }; - let Some(right) = right.as_f64() else { - return false; - }; - let scale = left.abs().max(right.abs()).max(1.0); - (left - right).abs() <= 1e-12 * scale - } - } -} - -fn json_semantically_equal(left: &Value, right: &Value) -> bool { - match (left, right) { - (Value::Null, Value::Null) => true, - (Value::Bool(a), Value::Bool(b)) => a == b, - (Value::Number(a), Value::Number(b)) => numbers_semantically_equal(a, b), - (Value::String(a), Value::String(b)) => a == b, - (Value::Array(a), Value::Array(b)) => { - a.len() == b.len() - && a.iter() - .zip(b.iter()) - .all(|(left, right)| json_semantically_equal(left, right)) - } - (Value::Object(a), Value::Object(b)) => { - a.len() == b.len() - && a.iter().all(|(key, left_value)| { - b.get(key) - .map(|right_value| json_semantically_equal(left_value, right_value)) - .unwrap_or(false) - }) - } - _ => false, - } -} +// ---- Self-consistency tests ---- #[test] -fn normalize_problem_instance_treats_reordered_ilp_as_equal() { - let problem = ProblemRef { - name: "ILP".to_string(), - variant: BTreeMap::from([("variable".to_string(), "bool".to_string())]), - }; - let canonical = ILP::::new( - 3, - vec![ - LinearConstraint::le(vec![(0, 1.0), (2, 1.0)], 1.0), - LinearConstraint::ge(vec![(1, 2.0), (0, 1.0)], 2.0), - ], - vec![(2, 3.0), (0, 1.0)], - ObjectiveSense::Maximize, - ); - let canonical = serde_json::to_value(&canonical).expect("ILP should serialize"); - - let reordered = ILP::::new( - 3, - vec![ - LinearConstraint::ge(vec![(0, 1.0), (1, 2.0)], 2.0), - LinearConstraint::le(vec![(2, 1.0), (0, 1.0)], 1.0), - ], - vec![(0, 1.0), (2, 3.0)], - ObjectiveSense::Maximize, - ); - let reordered = serde_json::to_value(&reordered).expect("ILP should serialize"); - - assert_eq!( - normalize_problem_instance(&problem, &canonical), - normalize_problem_instance(&problem, &reordered) - ); -} - -#[test] -fn json_semantically_equal_treats_tiny_float_roundoff_as_equal() { - let problem = ProblemRef { - name: "QUBO".to_string(), - variant: BTreeMap::from([("weight".to_string(), "f64".to_string())]), - }; - let canonical = QUBO::from_matrix(vec![vec![0.2, -1.5], vec![0.0, 1.0]]); - let canonical = normalize_problem_instance( - &problem, - &serde_json::to_value(&canonical).expect("QUBO should serialize"), - ); - - let noisy = QUBO::from_matrix(vec![vec![0.20000000000000018, -1.5], vec![0.0, 1.0]]); - let noisy = normalize_problem_instance( - &problem, - &serde_json::to_value(&noisy).expect("QUBO should serialize"), - ); - - assert!( - json_semantically_equal(&canonical, &noisy), - "tiny float noise should not count as a fixture mismatch" - ); -} - -#[test] -fn normalize_problem_instance_treats_reordered_graph_edges_as_equal() { - let problem = ProblemRef { - name: "MaximumMatching".to_string(), - variant: BTreeMap::from([ - ("graph".to_string(), "SimpleGraph".to_string()), - ("weight".to_string(), "i32".to_string()), - ]), - }; - let canonical = MaximumMatching::<_, i32>::new( - SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]), - vec![5, 7, 11], - ); - let canonical = serde_json::to_value(&canonical).expect("matching should serialize"); - - let reordered = MaximumMatching::<_, i32>::new( - SimpleGraph::new(4, vec![(2, 3), (0, 1), (1, 2)]), - vec![11, 5, 7], - ); - let reordered = serde_json::to_value(&reordered).expect("matching should serialize"); +fn model_specs_are_self_consistent() { + let specs = crate::models::graph::canonical_model_example_specs() + .into_iter() + .chain(crate::models::formula::canonical_model_example_specs()) + .chain(crate::models::set::canonical_model_example_specs()) + .chain(crate::models::algebraic::canonical_model_example_specs()) + .chain(crate::models::misc::canonical_model_example_specs()); - assert_eq!( - normalize_problem_instance(&problem, &canonical), - normalize_problem_instance(&problem, &reordered) - ); + for spec in specs { + let actual = spec.instance.evaluate_json(&spec.optimal_config); + assert_eq!( + actual, spec.optimal_value, + "Model spec '{}': evaluate(optimal_config) = {} but stored optimal_value = {}", + spec.id, actual, spec.optimal_value + ); + } } +#[cfg(feature = "ilp-solver")] #[test] -fn normalize_problem_instance_treats_reordered_spin_glass_interactions_as_equal() { - let problem = ProblemRef { - name: "SpinGlass".to_string(), - variant: BTreeMap::from([ - ("graph".to_string(), "SimpleGraph".to_string()), - ("weight".to_string(), "i32".to_string()), - ]), - }; - let canonical = SpinGlass::::new( - 3, - vec![((0, 1), 5), ((1, 2), -2), ((0, 2), 9)], - vec![1, 0, -1], - ); - let canonical = serde_json::to_value(&canonical).expect("spin glass should serialize"); - - let reordered = SpinGlass::::new( - 3, - vec![((0, 2), 9), ((0, 1), 5), ((1, 2), -2)], - vec![1, 0, -1], - ); - let reordered = serde_json::to_value(&reordered).expect("spin glass should serialize"); - - assert_eq!( - normalize_problem_instance(&problem, &canonical), - normalize_problem_instance(&problem, &reordered) - ); -} +fn model_specs_are_optimal() { + use crate::registry::find_variant_entry; + use crate::solvers::ILPSolver; -// ---- Fixture verification tests ---- -// These verify that stored fixtures are structurally and semantically -// consistent with freshly computed results. Rule fixture ordering can vary, -// so compare keyed content instead of relying on positional equality. + let ilp_solver = ILPSolver::new(); -#[test] -fn verify_model_fixtures_match_computed() { - let loaded = build_model_db().expect("fixture should load"); - let computed = compute_model_db().expect("compute should succeed"); - assert_eq!( - loaded.models.len(), - computed.models.len(), - "fixture and computed model counts differ — regenerate fixtures" - ); - for (loaded_model, computed_model) in loaded.models.iter().zip(computed.models.iter()) { - assert_eq!( - loaded_model.problem, computed_model.problem, - "model fixture mismatch for {} {:?} — problem name drifted", - loaded_model.problem, loaded_model.variant - ); - assert_eq!( - loaded_model.variant, computed_model.variant, - "model fixture mismatch for {} {:?} — variant drifted", - loaded_model.problem, loaded_model.variant - ); - let loaded_instance = - normalize_problem_instance(&loaded_model.problem_ref(), &loaded_model.instance); - let computed_instance = - normalize_problem_instance(&computed_model.problem_ref(), &computed_model.instance); - assert!( - json_semantically_equal(&loaded_instance, &computed_instance), - "model fixture instance mismatch for {} {:?} — regenerate fixtures with: \ - cargo run --release --example regenerate_fixtures --features \"ilp-highs example-db\"", - loaded_model.problem, - loaded_model.variant - ); - assert_eq!( - loaded_model.samples, computed_model.samples, - "model fixture sample evaluations mismatch for {} {:?} — regenerate fixtures with: \ - cargo run --release --example regenerate_fixtures --features \"ilp-highs example-db\"", - loaded_model.problem, loaded_model.variant - ); + let specs = crate::models::graph::canonical_model_example_specs() + .into_iter() + .chain(crate::models::formula::canonical_model_example_specs()) + .chain(crate::models::set::canonical_model_example_specs()) + .chain(crate::models::algebraic::canonical_model_example_specs()) + .chain(crate::models::misc::canonical_model_example_specs()); + + for spec in specs { + let name = spec.instance.problem_name(); + let variant = spec.instance.variant_map(); + + // Try ILP (direct or via reduction), fall back to brute force for small instances + let best_config = ilp_solver + .solve_via_reduction(name, &variant, spec.instance.as_any()) + .or_else(|| { + // Only brute-force if search space is small (≤ 2^20 configs) + let dims = spec.instance.dims_dyn(); + let log_space: f64 = dims.iter().map(|&d| (d as f64).log2()).sum(); + if log_space > 20.0 { + return None; + } + let entry = find_variant_entry(name, &variant)?; + let (config, _) = (entry.solve_fn)(spec.instance.as_any())?; + Some(config) + }) + .unwrap_or_else(|| { + panic!( + "No solver found for spec '{}' ({name} {variant:?})", + spec.id + ) + }); + + let best_value = spec.instance.evaluate_json(&best_config); assert_eq!( - loaded_model.optimal, computed_model.optimal, - "model fixture optima mismatch for {} {:?} — regenerate fixtures with: \ - cargo run --release --example regenerate_fixtures --features \"ilp-highs example-db\"", - loaded_model.problem, loaded_model.variant + best_value, spec.optimal_value, + "Model spec '{}': solver optimal = {} but stored optimal_value = {} \ + (solver config: {:?}, stored config: {:?})", + spec.id, best_value, spec.optimal_value, best_config, spec.optimal_config ); } } #[test] -fn verify_rule_fixtures_match_computed() { - let loaded = build_rule_db().expect("fixture should load"); - let computed = compute_rule_db().expect("computed rule db should build"); - assert_eq!( - loaded.rules.len(), - computed.rules.len(), - "fixture and computed rule counts differ — regenerate fixtures" - ); - let loaded_keys: BTreeSet<_> = loaded - .rules - .iter() - .map(|r| (r.source.problem_ref(), r.target.problem_ref())) - .collect(); - let computed_keys: BTreeSet<_> = computed - .rules - .iter() - .map(|r| (r.source.problem_ref(), r.target.problem_ref())) - .collect(); - assert_eq!( - loaded_keys, computed_keys, - "fixture and computed rule sets differ — regenerate fixtures" - ); - let loaded_by_key: BTreeMap<_, _> = loaded - .rules - .iter() - .map(|rule| ((rule.source.problem_ref(), rule.target.problem_ref()), rule)) - .collect(); - let computed_by_key: BTreeMap<_, _> = computed - .rules - .iter() - .map(|rule| ((rule.source.problem_ref(), rule.target.problem_ref()), rule)) - .collect(); +fn rule_specs_solution_pairs_are_consistent() { + let graph = ReductionGraph::new(); - for key in loaded_keys { - let loaded_rule = loaded_by_key - .get(&key) - .expect("loaded fixture key should exist"); - let computed_rule = computed_by_key - .get(&key) - .expect("computed fixture key should exist"); - - let loaded_source = normalize_problem_instance( - &loaded_rule.source.problem_ref(), - &loaded_rule.source.instance, - ); - let computed_source = normalize_problem_instance( - &computed_rule.source.problem_ref(), - &computed_rule.source.instance, - ); - assert!( - json_semantically_equal(&loaded_source, &computed_source), - "source instance mismatch for {} -> {} — regenerate fixtures", - loaded_rule.source.problem, - loaded_rule.target.problem - ); - let loaded_target = normalize_problem_instance( - &loaded_rule.target.problem_ref(), - &loaded_rule.target.instance, - ); - let computed_target = normalize_problem_instance( - &computed_rule.target.problem_ref(), - &computed_rule.target.instance, + let db = build_rule_db().unwrap(); + for example in &db.rules { + let label = format!( + "{} {:?} -> {} {:?}", + example.source.problem, + example.source.variant, + example.target.problem, + example.target.variant ); assert!( - json_semantically_equal(&loaded_target, &computed_target), - "target instance mismatch for {} -> {} — regenerate fixtures", - loaded_rule.source.problem, - loaded_rule.target.problem + !example.solutions.is_empty(), + "Rule {label} has no solution pairs" ); - // Solution witnesses may differ across platforms (ILP solver - // nondeterminism), so compare energy (objective value) rather than - // exact configs — both must be optimal. - assert_eq!( - loaded_rule.solutions.len(), - computed_rule.solutions.len(), - "solution count mismatch for {} -> {} — regenerate fixtures", - loaded_rule.source.problem, - loaded_rule.target.problem - ); - let label = format!( - "{} -> {}", - loaded_rule.source.problem, loaded_rule.target.problem - ); - for (loaded_pair, computed_pair) in loaded_rule - .solutions - .iter() - .zip(computed_rule.solutions.iter()) - { - let loaded_target_problem = load_dyn( - &loaded_rule.target.problem, - &loaded_rule.target.variant, - loaded_rule.target.instance.clone(), + + // Deserialize source and target via the registry so we can evaluate configs + let source = load_dyn( + &example.source.problem, + &example.source.variant, + example.source.instance.clone(), + ) + .unwrap_or_else(|e| panic!("Failed to load source for {label}: {e}")); + let target = load_dyn( + &example.target.problem, + &example.target.variant, + example.target.instance.clone(), + ) + .unwrap_or_else(|e| panic!("Failed to load target for {label}: {e}")); + + // Re-run the reduction to get extract_solution for round-trip check + let chain = graph + .reduce_along_path( + &graph + .find_cheapest_path( + &example.source.problem, + &example.source.variant, + &example.target.problem, + &example.target.variant, + &crate::types::ProblemSize::new(vec![]), + &crate::rules::MinimizeSteps, + ) + .unwrap_or_else(|| panic!("No reduction path for {label}")), + source.as_any(), ) - .unwrap_or_else(|e| panic!("{label}: load target: {e}")); - let loaded_energy = loaded_target_problem.evaluate_dyn(&loaded_pair.target_config); - let computed_energy = loaded_target_problem.evaluate_dyn(&computed_pair.target_config); + .unwrap_or_else(|| panic!("Failed to reduce along path for {label}")); + + for pair in &example.solutions { + // Verify config lengths match problem dimensions + assert_eq!( + pair.source_config.len(), + source.dims_dyn().len(), + "Rule {label}: source_config length {} != dims length {}", + pair.source_config.len(), + source.dims_dyn().len() + ); + assert_eq!( + pair.target_config.len(), + target.dims_dyn().len(), + "Rule {label}: target_config length {} != dims length {}", + pair.target_config.len(), + target.dims_dyn().len() + ); + // Verify configs produce non-Invalid / non-false evaluations + let source_val = source.evaluate_json(&pair.source_config); + let target_val = target.evaluate_json(&pair.target_config); + assert_ne!( + source_val, + serde_json::json!("Invalid"), + "Rule {label}: source_config evaluates to Invalid" + ); + assert_ne!( + target_val, + serde_json::json!("Invalid"), + "Rule {label}: target_config evaluates to Invalid" + ); + assert_ne!( + source_val, + serde_json::json!(false), + "Rule {label}: source_config evaluates to false" + ); + assert_ne!( + target_val, + serde_json::json!(false), + "Rule {label}: target_config evaluates to false" + ); + // Round-trip: extract_solution(target_config) must produce a valid + // source config with the same evaluation value + let extracted = chain.extract_solution(&pair.target_config); + let extracted_val = source.evaluate_json(&extracted); assert_eq!( - loaded_energy, computed_energy, - "{label}: target energy mismatch — regenerate fixtures" + extracted_val, source_val, + "Rule {label}: round-trip value mismatch: \ + evaluate(extract_solution(target_config)) = {} but evaluate(source_config) = {} \ + (extracted: {:?}, stored: {:?})", + extracted_val, source_val, extracted, pair.source_config ); } } diff --git a/src/unit_tests/export.rs b/src/unit_tests/export.rs index 8b02dc623..27776a8cf 100644 --- a/src/unit_tests/export.rs +++ b/src/unit_tests/export.rs @@ -42,27 +42,14 @@ fn test_lookup_overhead_unknown_reduction() { assert!(result.is_none()); } -#[test] -fn test_write_canonical_example_db() { - use std::fs; - use std::time::{SystemTime, UNIX_EPOCH}; - - let dir = std::env::temp_dir().join(format!( - "problemreductions-export-db-test-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() - )); - fs::create_dir_all(&dir).unwrap(); - - let db = ExampleDb { +fn sample_example_db() -> ExampleDb { + ExampleDb { models: vec![ModelExample { problem: "ModelProblem".to_string(), variant: variant_to_map(vec![("graph", "SimpleGraph")]), instance: serde_json::json!({"n": 5}), - samples: vec![], - optimal: vec![], + optimal_config: vec![], + optimal_value: serde_json::json!(null), }], rules: vec![RuleExample { source: ProblemSide { @@ -77,65 +64,29 @@ fn test_write_canonical_example_db() { }, solutions: vec![], }], - }; - write_example_db_to(&dir, &db); - - let examples_json: serde_json::Value = - serde_json::from_str(&fs::read_to_string(dir.join("examples.json")).unwrap()).unwrap(); - - assert_eq!( - examples_json["rules"][0]["source"]["problem"], - "SourceProblem" - ); - assert_eq!(examples_json["models"][0]["problem"], "ModelProblem"); - assert!( - !dir.join("rules.json").exists(), - "canonical export should not split rules into a separate file" - ); - assert!( - !dir.join("models.json").exists(), - "canonical export should not split models into a separate file" - ); - - let _ = fs::remove_dir_all(&dir); + } } -#[test] -fn test_write_example_db_uses_wrapped_json_contract() { - use std::fs; +fn export_test_dir(label: &str) -> std::path::PathBuf { use std::time::{SystemTime, UNIX_EPOCH}; - let dir = std::env::temp_dir().join(format!( - "problemreductions-export-db-contract-test-{}", + "problemreductions-export-{}-{}", + label, SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_nanos() )); - fs::create_dir_all(&dir).unwrap(); + std::fs::create_dir_all(&dir).unwrap(); + dir +} - let db = ExampleDb { - models: vec![ModelExample { - problem: "ModelProblem".to_string(), - variant: variant_to_map(vec![("graph", "SimpleGraph")]), - instance: serde_json::json!({"n": 5}), - samples: vec![], - optimal: vec![], - }], - rules: vec![RuleExample { - source: ProblemSide { - problem: "SourceProblem".to_string(), - variant: variant_to_map(vec![("graph", "SimpleGraph")]), - instance: serde_json::json!({"n": 3}), - }, - target: ProblemSide { - problem: "TargetProblem".to_string(), - variant: variant_to_map(vec![("weight", "i32")]), - instance: serde_json::json!({"m": 4}), - }, - solutions: vec![], - }], - }; +#[test] +fn test_write_canonical_example_db() { + use std::fs; + + let dir = export_test_dir("db-test"); + let db = sample_example_db(); write_example_db_to(&dir, &db); let examples_json: serde_json::Value = @@ -146,6 +97,14 @@ fn test_write_example_db_uses_wrapped_json_contract() { "SourceProblem" ); assert_eq!(examples_json["models"][0]["problem"], "ModelProblem"); + assert!( + !dir.join("rules.json").exists(), + "canonical export should not split rules into a separate file" + ); + assert!( + !dir.join("models.json").exists(), + "canonical export should not split models into a separate file" + ); let _ = fs::remove_dir_all(&dir); } @@ -153,45 +112,19 @@ fn test_write_example_db_uses_wrapped_json_contract() { #[test] fn test_write_example_db_uses_one_line_per_example_entry() { use std::fs; - use std::time::{SystemTime, UNIX_EPOCH}; - let dir = std::env::temp_dir().join(format!( - "problemreductions-export-db-lines-test-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos() - )); - fs::create_dir_all(&dir).unwrap(); - - let db = ExampleDb { - models: vec![ModelExample { - problem: "ModelProblem".to_string(), - variant: variant_to_map(vec![("graph", "SimpleGraph")]), - instance: serde_json::json!({"n": 5, "edges": [[0, 1], [1, 2]]}), - samples: vec![SampleEval { - config: vec![1, 0, 1], - metric: serde_json::json!({"Valid": 2}), - }], - optimal: vec![], - }], - rules: vec![RuleExample { - source: ProblemSide { - problem: "SourceProblem".to_string(), - variant: variant_to_map(vec![("graph", "SimpleGraph")]), - instance: serde_json::json!({"n": 3, "edges": [[0, 1], [1, 2]]}), - }, - target: ProblemSide { - problem: "TargetProblem".to_string(), - variant: variant_to_map(vec![("weight", "i32")]), - instance: serde_json::json!({"m": 4, "weights": [1, 2, 3, 4]}), - }, - solutions: vec![SolutionPair { - source_config: vec![1, 0, 1], - target_config: vec![0, 1, 1, 0], - }], - }], - }; + let dir = export_test_dir("db-lines-test"); + let mut db = sample_example_db(); + // Add richer data so the one-line-per-entry format is meaningful + db.models[0].instance = serde_json::json!({"n": 5, "edges": [[0, 1], [1, 2]]}); + db.models[0].optimal_config = vec![1, 0, 1]; + db.models[0].optimal_value = serde_json::json!({"Valid": 2}); + db.rules[0].source.instance = serde_json::json!({"n": 3, "edges": [[0, 1], [1, 2]]}); + db.rules[0].target.instance = serde_json::json!({"m": 4, "weights": [1, 2, 3, 4]}); + db.rules[0].solutions = vec![SolutionPair { + source_config: vec![1, 0, 1], + target_config: vec![0, 1, 1, 0], + }]; write_example_db_to(&dir, &db); let text = fs::read_to_string(dir.join("examples.json")).unwrap(); @@ -274,7 +207,7 @@ fn export_variant_to_map_preserves_explicit_graph() { assert_eq!(map["weight"], "f64"); } -// ---- ProblemSide::from_problem / ModelExample::from_problem ---- +// ---- ProblemSide::from_problem / ModelExample::new ---- #[test] fn problem_side_from_typed_problem() { @@ -290,20 +223,17 @@ fn problem_side_from_typed_problem() { } #[test] -fn model_example_from_typed_problem() { - use crate::models::graph::MaximumIndependentSet; - use crate::topology::SimpleGraph; - - let g = SimpleGraph::new(3, vec![(0, 1), (1, 2)]); - let mis = MaximumIndependentSet::new(g, vec![1, 1, 1]); - let sample = SampleEval { - config: vec![1, 0, 1], - metric: serde_json::json!("Valid(2)"), - }; - let example = ModelExample::from_problem(&mis, vec![sample.clone()], vec![sample]); +fn model_example_new() { + let example = ModelExample::new( + "MaximumIndependentSet", + variant_to_map(vec![("graph", "SimpleGraph"), ("weight", "i32")]), + serde_json::json!({"num_vertices": 3, "edges": [[0, 1], [1, 2]]}), + vec![1, 0, 1], + serde_json::json!({"Valid": 2}), + ); assert_eq!(example.problem, "MaximumIndependentSet"); - assert!(!example.samples.is_empty()); - assert!(!example.optimal.is_empty()); + assert_eq!(example.optimal_config, vec![1, 0, 1]); + assert_eq!(example.optimal_value, serde_json::json!({"Valid": 2})); assert!(example.instance.is_object()); } @@ -313,8 +243,8 @@ fn model_example_problem_ref() { problem: "TestProblem".to_string(), variant: variant_to_map(vec![("graph", "SimpleGraph")]), instance: serde_json::json!({}), - samples: vec![], - optimal: vec![], + optimal_config: vec![], + optimal_value: serde_json::json!(null), }; let pref = example.problem_ref(); assert_eq!(pref.name, "TestProblem"); @@ -324,13 +254,7 @@ fn model_example_problem_ref() { #[test] fn write_rule_example_to_creates_json_file() { use std::fs; - let dir = std::env::temp_dir().join(format!( - "pr-export-rule-example-{}", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos() - )); + let dir = export_test_dir("rule-example"); let example = RuleExample { source: ProblemSide { problem: "A".to_string(), @@ -356,22 +280,13 @@ fn write_rule_example_to_creates_json_file() { #[test] fn write_model_example_to_creates_json_file() { use std::fs; - let dir = std::env::temp_dir().join(format!( - "pr-export-model-example-{}", - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos() - )); + let dir = export_test_dir("model-example"); let example = ModelExample { problem: "TestModel".to_string(), variant: variant_to_map(vec![("graph", "SimpleGraph")]), instance: serde_json::json!({"n": 3}), - samples: vec![SampleEval { - config: vec![1, 0, 1], - metric: serde_json::json!("Valid(2)"), - }], - optimal: vec![], + optimal_config: vec![1, 0, 1], + optimal_value: serde_json::json!({"Valid": 2}), }; write_model_example_to(&dir, "test_model", &example); let path = dir.join("test_model.json"); diff --git a/src/unit_tests/models/graph/multiple_choice_branching.rs b/src/unit_tests/models/graph/multiple_choice_branching.rs index 0317948c9..9d31d30ed 100644 --- a/src/unit_tests/models/graph/multiple_choice_branching.rs +++ b/src/unit_tests/models/graph/multiple_choice_branching.rs @@ -205,7 +205,7 @@ fn test_multiple_choice_branching_serialization() { #[test] fn test_multiple_choice_branching_deserialize_rejects_weight_length_mismatch() { let json = r#"{ - "graph": {"inner": {"nodes": [null, null], "node_holes": [], "edge_property": "directed", "edges": [[0, 1, null]]}}, + "graph": {"num_vertices": 2, "arcs": [[0, 1]]}, "weights": [1, 2], "partition": [[0]], "threshold": 1 @@ -218,7 +218,7 @@ fn test_multiple_choice_branching_deserialize_rejects_weight_length_mismatch() { #[test] fn test_multiple_choice_branching_deserialize_rejects_invalid_partition() { let json = r#"{ - "graph": {"inner": {"nodes": [null, null], "node_holes": [], "edge_property": "directed", "edges": [[0, 1, null]]}}, + "graph": {"num_vertices": 2, "arcs": [[0, 1]]}, "weights": [1], "partition": [[1]], "threshold": 1 diff --git a/src/unit_tests/topology/directed_graph.rs b/src/unit_tests/topology/directed_graph.rs index 2a668b39f..086728ae0 100644 --- a/src/unit_tests/topology/directed_graph.rs +++ b/src/unit_tests/topology/directed_graph.rs @@ -208,6 +208,27 @@ fn test_directed_graph_serialization() { assert_eq!(g, restored); } +#[test] +fn test_directed_graph_json_roundtrip() { + let g = DirectedGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]); + let json = serde_json::to_value(&g).unwrap(); + assert_eq!(json["num_vertices"], 4); + let arcs: Vec<(usize, usize)> = serde_json::from_value(json["arcs"].clone()).unwrap(); + assert_eq!(arcs.len(), 3); + let roundtrip: DirectedGraph = serde_json::from_value(json).unwrap(); + assert_eq!(g, roundtrip); +} + +#[test] +fn test_directed_graph_json_format() { + let g = DirectedGraph::new(3, vec![(0, 1), (1, 2)]); + let json_str = serde_json::to_string(&g).unwrap(); + assert!(!json_str.contains("edge_property")); + assert!(!json_str.contains("node_holes")); + assert!(json_str.contains("num_vertices")); + assert!(json_str.contains("arcs")); +} + #[test] #[should_panic(expected = "arc (0, 5) references vertex >= num_vertices")] fn test_directed_graph_invalid_arc() { diff --git a/src/unit_tests/topology/graph.rs b/src/unit_tests/topology/graph.rs index a4e01d930..da89fb5ba 100644 --- a/src/unit_tests/topology/graph.rs +++ b/src/unit_tests/topology/graph.rs @@ -133,3 +133,23 @@ fn test_simple_graph_eq_different_sizes() { let g2 = SimpleGraph::new(4, vec![(0, 1)]); // Different vertex count assert_ne!(g1, g2); } + +#[test] +fn test_simplegraph_json_roundtrip() { + let graph = SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]); + let json = serde_json::to_value(&graph).unwrap(); + assert_eq!(json["num_vertices"], 4); + let edges: Vec<(usize, usize)> = serde_json::from_value(json["edges"].clone()).unwrap(); + assert_eq!(edges.len(), 3); + let roundtrip: SimpleGraph = serde_json::from_value(json).unwrap(); + assert_eq!(graph, roundtrip); +} + +#[test] +fn test_simplegraph_json_format() { + let graph = SimpleGraph::new(3, vec![(0, 1), (1, 2)]); + let json_str = serde_json::to_string(&graph).unwrap(); + assert!(!json_str.contains("edge_property")); + assert!(!json_str.contains("node_holes")); + assert!(json_str.contains("num_vertices")); +}