Skip to content

Commit c57a131

Browse files
GiggleLiuclaude
andauthored
feat: batch implement 17 reduction rules with 14 new models (#999)
* feat: add SubsetSum → Partition reduction rule (#973) Implements the classical padding reduction from Garey & Johnson (SP12-SP13). Handles all three cases: Σ=2T (no padding), Σ>2T (same-side extraction), and Σ<2T (opposite-side extraction). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add NonTautology model and Satisfiability → NonTautology rule (#868) Adds the NonTautology (DNF falsifiability) model with Value=Or, and the De Morgan negation reduction from Satisfiability. Each CNF clause becomes a DNF disjunct with flipped literal signs; solution extraction is identity. Includes CLI/MCP support for NonTautology creation and example-db hooks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add PartitionIntoCliques model and KColoring → PartitionIntoCliques rule (#844) Adds the PartitionIntoCliques graph model (Value=Or, partitions vertices into K cliques) and the complement-graph reduction from KColoring. Color classes in G become cliques in the complement graph. Includes CLI support, example-db entries, paper documentation, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add Kernel model and 3SAT → Kernel reduction rule (#882) Adds the Kernel model for directed graphs (Value=Or, independent + absorbing vertex set) and Chvátal's 1973 reduction from KSatisfiability<K3>. Variable digons encode truth assignments; directed 3-cycles with connection arcs enforce clause satisfaction via the absorption property. Includes CLI support, example-db entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add DegreeConstrainedSpanningTree model and HamPath → DCST rule (#911) Adds DegreeConstrainedSpanningTree graph model (Value=Or, edge-selection configs checked for spanning tree + degree bound) and the identity reduction from HamiltonianPath with K=2. A degree-2 spanning tree is exactly a Hamiltonian path. Includes CLI support, example-db entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add SetSplitting model and NAE-SAT → SetSplitting rule (#382) Adds the SetSplitting (hypergraph 2-colorability) model with Value=Or, and the reduction from NAESatisfiability. Uses two elements per variable (positive/negative literal) with pairing subsets to enforce complementary assignment, plus one subset per clause to enforce non-monochromatic NAE. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add SubsetProduct model and X3C → SubsetProduct rule (#388) Adds SubsetProduct model (Value=Or, binary subset selection with product check) and the prime-encoding reduction from ExactCoverBy3Sets. Each universe element gets a distinct prime; each 3-set maps to the product of its elements' primes. By FTA, subset product equals universe product iff the selected sets form an exact cover. Includes CLI support and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add IntegerExpressionMembership model and SubsetSum → IEM rule (#569) Adds IntegerExpressionMembership (pick-one-per-position sum check with Value=Or) and the shift-encoding reduction from SubsetSum. Each element a_i creates choice set {1, a_i+1}; target K = B + n. Picking a_i+1 means "include element"; sum equals K iff selected elements sum to B. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add MinimumWeightSolutionToLinearEquations model and X3C → MWSLE rule (#860) Adds MWSLE algebraic model (Value=Or, binary variables with linear equation check + sparsity bound) and the incidence-matrix reduction from ExactCoverBy3Sets. One variable per 3-set, one equation per universe element, bound K = |U|/3. Exact cover iff equation system has K-sparse solution. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add SimultaneousIncongruences model and 3SAT → SI rule (#554) Adds SimultaneousIncongruences algebraic model (Value=Or, find x in [1..N] satisfying all x mod m_i != r_i) and the CRT-based reduction from KSatisfiability<K3>. Each variable gets a distinct odd prime, residues 1/2 encode true/false, other residues are forbidden, and each clause adds one CRT-derived forbidden residue. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add SequencingToMinimizeTardyTaskWeight model and Partition → SMTTW rule (#471) Adds SequencingToMinimizeTardyTaskWeight model (Value=Min<u64>, Lehmer-coded permutation schedules) and the common-deadline reduction from Partition. Each element becomes a task with length=weight=size and deadline=B/2. On-time tasks decode one partition half. Includes CLI support and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add OpenShopScheduling model and Partition → OSS rule (#481) Adds OpenShopScheduling model (Value=Min<u64>, Lehmer-coded permutation schedules with active-schedule decoder) and the Gonzalez-Sahni 1976 reduction from Partition. Uses 3 machines with a special Q-job; makespan ≤3Q iff balanced partition exists. Includes CLI support and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add NAESatisfiability → MaxCut reduction rule (#166) Implements the Garey-Johnson-Stockmeyer 1976 reduction. Variable edges with weight M=2m+1 force complementary partition; clause triangles with unit weights contribute exactly 2 cut edges per NAE-satisfied clause. Max cut ≥ nM+2m iff NAE-satisfiable. Includes paper entry, canonical example, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add IsomorphicSpanningTree model and HamPath → IST rule (#912) Adds IsomorphicSpanningTree graph model (Value=Or, permutation-based isomorphism check) and the identity reduction from HamiltonianPath with tree T=P_n. A spanning tree isomorphic to a path is exactly a Hamiltonian path. Includes CLI support, updated ILP rule, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add AlgebraicEquationsOverGF2 model and X3C → AEGF2 rule (#859) Adds AlgebraicEquationsOverGF2 model (Value=Or, polynomial system over GF(2) with XOR/AND evaluation) and the Fraenkel-Yesha 1977 reduction from ExactCoverBy3Sets. Linear equations enforce odd-cover per element; pairwise product equations forbid double-cover. Together they force exactly-one cover. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add ProductionPlanning model and Partition → PP rule (#488) Adds ProductionPlanning model (Value=Or, lot-sizing with setup/production/ inventory costs and a total cost bound) and the Lenstra-Rinnooy Kan-Florian 1978 reduction from Partition. Element items map to production periods; a terminal demand period consumes S/2; balanced partition iff feasible production plan within cost bound. Includes CLI support, paper entries, and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add HamiltonianPathBetweenTwoVertices → LongestPath reduction rule (#359) Copy graph with unit edge weights and same s/t vertices. A Hamiltonian s-t path has n-1 edges = maximum possible simple path length. Solution extraction walks selected edges from source to reconstruct the vertex permutation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove stray prompt.md and implementation_log.md These were working files from the batch implementation session, not intended for the repository. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address PR #999 review issues * update rules note * docs: add Source Material section to write-rule-in-paper skill Adds guidance to consult GitHub issues and derivation documents as primary sources for mathematical content, rather than inventing proofs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: augment 18 paper entries with examples, citations, and pred-commands Each reduction-rule entry now includes: - load-example data bindings and example: true parameter - Complexity citation (@garey1979, @karp1972, etc.) - Worked example with pred-commands() reproducibility block - Step-by-step verification using fixture data Fixed entry #13 (NAE-SAT → MaxCut): proper @citation. Fixed entry #18 (GraphPartitioning → MaxCut): completed proof replacing $= dots$ placeholder with full derivation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add explicit GraphPartitioning name resolution for CI determinism The inventory-based registry resolution is non-deterministic across platforms. On CI, "GraphPartitioning" was resolving to "MaxCut" due to registration order, causing test_create_graph_partitioning to fail. Add explicit case-insensitive resolution, matching the pattern used for other ambiguous problem names. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: align 3 paper entries with implemented code (Kernel, MaxCut, GraphPartitioning) - KSatisfiability → Kernel: corrected arc count to 2n+6m, rewrote proof to allow clause vertices in kernel matching the actual code - NAESatisfiability → MaxCut: corrected M = m+1 (was 2m+1), fixed example - GraphPartitioning → MaxCut: completed balance proof via P=|E|+1 penalty All examples now use load-example() fixture data with pred-commands(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs: expand 9 paper examples with concrete fixture data and step-by-step verification Expanded worked examples for: NAE-SAT→SetSplitting, X3C→SubsetProduct, SubsetSum→IntegerExprMembership, X3C→MWSLE, 3SAT→SimultaneousIncongruences, Partition→SeqMinTardyTaskWeight, Partition→OpenShopScheduling, X3C→AlgEqOverGF2, Partition→ProductionPlanning. Each example now shows construction with actual numbers from load-example() fixtures and step-by-step witness verification. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 61f059c commit c57a131

66 files changed

Lines changed: 5077 additions & 167 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/write-rule-in-paper/SKILL.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ Before using this skill, ensure:
2121
- If the canonical example changed, fixtures are regenerated (`make regenerate-fixtures`)
2222
- The reduction graph and schemas are up to date (`cargo run --example export_graph && cargo run --example export_schemas`)
2323

24+
## Source Material
25+
26+
For mathematical content (theorems, proofs, examples), consult these sources in priority order:
27+
1. **GitHub issue** for the rule (`gh issue view <number>`): contains the verified reduction algorithm, correctness proof, size overhead, and worked examples written during issue creation
28+
2. **Derivation documents** (if available): e.g., `~/Downloads/reduction_derivations_*.typ` — these contain batch-verified proofs with explicit theorem/proof blocks
29+
3. **The implementation** (`src/rules/<source>_<target>.rs`): the code is the ground truth for the construction
30+
31+
Do NOT invent proofs — always cross-check against the issue and derivation sources. The issue body typically has: Reduction Algorithm, Correctness (forward/backward), Size Overhead, Example, and References sections that map directly to the paper entry structure.
32+
2433
## Step 1: Load Example Data
2534

2635
```typst

docs/paper/reductions.typ

Lines changed: 761 additions & 0 deletions
Large diffs are not rendered by default.

problemreductions-cli/src/cli.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,9 +220,11 @@ Flags by problem type:
220220
LongestPath --graph, --edge-lengths, --source-vertex, --target-vertex
221221
HamiltonianPathBetweenTwoVertices --graph, --source-vertex, --target-vertex
222222
ShortestWeightConstrainedPath --graph, --edge-lengths, --edge-weights, --source-vertex, --target-vertex, --weight-bound
223+
GraphPartitioning --graph, --num-partitions
223224
MaximalIS --graph, --weights
224225
SAT, NAESAT --num-vars, --clauses
225226
KSAT --num-vars, --clauses [--k]
227+
NonTautology --num-vars, --disjuncts
226228
QUBO --matrix
227229
SpinGlass --graph, --couplings, --fields
228230
KColoring --graph, --k
@@ -370,6 +372,7 @@ Examples:
370372
pred create --example MVC/SimpleGraph/i32 --to MIS/SimpleGraph/i32 --example-side target
371373
pred create MIS --graph 0-1,1-2,2-3 --weights 1,1,1
372374
pred create SAT --num-vars 3 --clauses \"1,2;-1,3\"
375+
pred create NonTautology --num-vars 3 --disjuncts \"1,2,3;-1,-2,-3\"
373376
pred create QUBO --matrix \"1,0.5;0.5,2\"
374377
pred create CapacityAssignment --capacities 1,2,3 --cost-matrix \"1,3,6;2,4,7;1,2,5\" --delay-matrix \"8,4,1;7,3,1;6,3,1\" --cost-budget 10 --delay-budget 12
375378
pred create ProductionPlanning --num-periods 6 --demands 5,3,7,2,8,5 --capacities 12,12,12,12,12,12 --setup-costs 10,10,10,10,10,10 --production-costs 1,1,1,1,1,1 --inventory-costs 1,1,1,1,1,1 --cost-bound 80
@@ -474,6 +477,9 @@ pub struct CreateArgs {
474477
/// Clauses for SAT problems (semicolon-separated, e.g., "1,2;-1,3")
475478
#[arg(long)]
476479
pub clauses: Option<String>,
480+
/// Disjuncts for NonTautology (semicolon-separated, e.g., "1,2;-1,3")
481+
#[arg(long)]
482+
pub disjuncts: Option<String>,
477483
/// Number of variables (for SAT/KSAT)
478484
#[arg(long)]
479485
pub num_vars: Option<usize>,
@@ -484,6 +490,9 @@ pub struct CreateArgs {
484490
/// Shared integer parameter (use `pred create <PROBLEM>` for the problem-specific meaning)
485491
#[arg(long)]
486492
pub k: Option<usize>,
493+
/// Number of partitions for GraphPartitioning (currently must be 2)
494+
#[arg(long)]
495+
pub num_partitions: Option<usize>,
487496
/// Generate a random instance (graph-based problems only)
488497
#[arg(long)]
489498
pub random: bool,

problemreductions-cli/src/commands/create.rs

Lines changed: 136 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use problemreductions::models::algebraic::{
1616
};
1717
use problemreductions::models::formula::Quantifier;
1818
use problemreductions::models::graph::{
19-
DirectedHamiltonianPath, DisjointConnectingPaths, GeneralizedHex, HamiltonianCircuit,
20-
HamiltonianPath, HamiltonianPathBetweenTwoVertices, IntegralFlowBundles, Kernel,
21-
LengthBoundedDisjointPaths, LongestCircuit, LongestPath, MinimumCutIntoBoundedSets,
19+
DirectedHamiltonianPath, DisjointConnectingPaths, GeneralizedHex, GraphPartitioning,
20+
HamiltonianCircuit, HamiltonianPath, HamiltonianPathBetweenTwoVertices, IntegralFlowBundles,
21+
Kernel, LengthBoundedDisjointPaths, LongestCircuit, LongestPath, MinimumCutIntoBoundedSets,
2222
MinimumDummyActivitiesPert, MinimumGeometricConnectedDominatingSet, MinimumMaximalMatching,
2323
MinimumMultiwayCut, MixedChinesePostman, MultipleChoiceBranching, PathConstrainedNetworkFlow,
2424
RootedTreeArrangement, SteinerTree, SteinerTreeInGraphs, StrongConnectivityAugmentation,
@@ -90,9 +90,11 @@ fn all_data_flags_empty(args: &CreateArgs) -> bool {
9090
&& args.couplings.is_none()
9191
&& args.fields.is_none()
9292
&& args.clauses.is_none()
93+
&& args.disjuncts.is_none()
9394
&& args.num_vars.is_none()
9495
&& args.matrix.is_none()
9596
&& args.k.is_none()
97+
&& args.num_partitions.is_none()
9698
&& args.target.is_none()
9799
&& args.m.is_none()
98100
&& args.n.is_none()
@@ -657,6 +659,7 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str {
657659
"HamiltonianPathBetweenTwoVertices" => {
658660
"--graph 0-1,0-3,1-2,1-4,2-5,3-4,4-5,2-3 --source-vertex 0 --target-vertex 5"
659661
}
662+
"GraphPartitioning" => "--graph 0-1,1-2,2-3,3-0 --num-partitions 2",
660663
"LongestPath" => {
661664
"--graph 0-1,0-2,1-3,2-3,2-4,3-5,4-5,4-6,5-6,1-6 --edge-lengths 3,2,4,1,5,2,3,2,4,1 --source-vertex 0 --target-vertex 6"
662665
}
@@ -707,7 +710,7 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str {
707710
"KSatisfiability" => "--num-vars 3 --clauses \"1,2,3;-1,2,-3\" --k 3",
708711
"Maximum2Satisfiability" => "--num-vars 4 --clauses \"1,2;1,-2;-1,3;-1,-3;2,4;-3,-4;3,4\"",
709712
"NonTautology" => {
710-
"--num-vars 3 --clauses \"1,2,3;-1,-2,-3\""
713+
"--num-vars 3 --disjuncts \"1,2,3;-1,-2,-3\""
711714
}
712715
"OneInThreeSatisfiability" => {
713716
"--num-vars 4 --clauses \"1,2,3;-1,3,4;2,-3,-4\""
@@ -1092,6 +1095,7 @@ fn help_flag_hint(
10921095
("MinimumCodeGenerationParallelAssignments", "assignments") => {
10931096
"semicolon-separated target:reads entries: \"0:1,2;1:0;2:3;3:1,2\""
10941097
}
1098+
("NonTautology", "disjuncts") => "semicolon-separated disjuncts: \"1,2,3;-1,-2,-3\"",
10951099
("TimetableDesign", "craftsman_avail") | ("TimetableDesign", "task_avail") => {
10961100
"semicolon-separated 0/1 rows: \"1,1,0;0,1,1\""
10971101
}
@@ -1212,6 +1216,12 @@ fn print_problem_help(canonical: &str, graph_type: Option<&str>) -> Result<()> {
12121216
eprintln!(" --{:<16} {} ({})", flag_name, field.description, hint);
12131217
}
12141218
}
1219+
if canonical == "GraphPartitioning" {
1220+
eprintln!(
1221+
" --{:<16} Number of partitions in the balanced partitioning model (must be 2) (integer)",
1222+
"num-partitions"
1223+
);
1224+
}
12151225
} else {
12161226
bail!("{}", crate::problem_name::unknown_problem_error(canonical));
12171227
}
@@ -1762,6 +1772,23 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> {
17621772
)
17631773
}
17641774

1775+
"GraphPartitioning" => {
1776+
let usage = "pred create GraphPartitioning --graph 0-1,1-2,2-3,3-0 --num-partitions 2";
1777+
let (graph, _) =
1778+
parse_graph(args).map_err(|e| anyhow::anyhow!("{e}\n\nUsage: {usage}"))?;
1779+
let num_partitions = args.num_partitions.ok_or_else(|| {
1780+
anyhow::anyhow!("GraphPartitioning requires --num-partitions\n\nUsage: {usage}")
1781+
})?;
1782+
anyhow::ensure!(
1783+
num_partitions == 2,
1784+
"GraphPartitioning currently models balanced bipartition only, so --num-partitions must be 2 (got {num_partitions})"
1785+
);
1786+
(
1787+
ser(GraphPartitioning::new(graph))?,
1788+
resolved_variant.clone(),
1789+
)
1790+
}
1791+
17651792
// LongestPath
17661793
"LongestPath" => {
17671794
let usage = "pred create LongestPath --graph 0-1,0-2,1-3,2-3,2-4,3-5,4-5,4-6,5-6,1-6 --edge-lengths 3,2,4,1,5,2,3,2,4,1 --source-vertex 0 --target-vertex 6";
@@ -2397,13 +2424,11 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> {
23972424
let num_vars = args.num_vars.ok_or_else(|| {
23982425
anyhow::anyhow!(
23992426
"NonTautology requires --num-vars\n\n\
2400-
Usage: pred create NonTautology --num-vars 3 --clauses \"1,2,3;-1,-2,-3\""
2427+
Usage: pred create NonTautology --num-vars 3 --disjuncts \"1,2,3;-1,-2,-3\""
24012428
)
24022429
})?;
2403-
let clauses = parse_clauses(args)?;
2404-
let disjuncts: Vec<Vec<i32>> = clauses.into_iter().map(|c| c.literals).collect();
24052430
(
2406-
ser(NonTautology::new(num_vars, disjuncts))?,
2431+
ser(NonTautology::new(num_vars, parse_disjuncts(args)?))?,
24072432
resolved_variant.clone(),
24082433
)
24092434
}
@@ -7360,6 +7385,28 @@ fn parse_clauses(args: &CreateArgs) -> Result<Vec<CNFClause>> {
73607385
.collect()
73617386
}
73627387

7388+
fn parse_disjuncts(args: &CreateArgs) -> Result<Vec<Vec<i32>>> {
7389+
let disjuncts_str = args
7390+
.disjuncts
7391+
.as_deref()
7392+
.or(args.clauses.as_deref())
7393+
.ok_or_else(|| {
7394+
anyhow::anyhow!("NonTautology requires --disjuncts (e.g., \"1,2,3;-1,-2,-3\")")
7395+
})?;
7396+
7397+
disjuncts_str
7398+
.split(';')
7399+
.map(|disjunct| {
7400+
disjunct
7401+
.trim()
7402+
.split(',')
7403+
.map(|s| s.trim().parse::<i32>())
7404+
.collect::<std::result::Result<Vec<_>, _>>()
7405+
.map_err(anyhow::Error::from)
7406+
})
7407+
.collect()
7408+
}
7409+
73637410
/// Parse `--sets` as semicolon-separated sets of comma-separated usize.
73647411
/// E.g., "0,1;1,2;0,2"
73657412
fn parse_sets(args: &CreateArgs) -> Result<Vec<Vec<usize>>> {
@@ -9901,9 +9948,11 @@ mod tests {
99019948
couplings: None,
99029949
fields: None,
99039950
clauses: None,
9951+
disjuncts: None,
99049952
num_vars: None,
99059953
matrix: None,
99069954
k: None,
9955+
num_partitions: None,
99079956
random: false,
99089957
source_vertex: None,
99099958
target_vertex: None,
@@ -10843,6 +10892,85 @@ mod tests {
1084310892
assert!(err.contains("bound >= 1"));
1084410893
}
1084510894

10895+
#[test]
10896+
fn test_create_graph_partitioning_with_num_partitions() {
10897+
use crate::dispatch::ProblemJsonOutput;
10898+
use problemreductions::models::graph::GraphPartitioning;
10899+
use problemreductions::topology::SimpleGraph;
10900+
10901+
let cli = Cli::try_parse_from([
10902+
"pred",
10903+
"create",
10904+
"GraphPartitioning",
10905+
"--graph",
10906+
"0-1,1-2,2-3,3-0",
10907+
"--num-partitions",
10908+
"2",
10909+
])
10910+
.unwrap();
10911+
let args = match cli.command {
10912+
Commands::Create(args) => args,
10913+
_ => unreachable!(),
10914+
};
10915+
10916+
let output_path = temp_output_path("graph-partitioning-create");
10917+
let out = OutputConfig {
10918+
output: Some(output_path.clone()),
10919+
quiet: true,
10920+
json: false,
10921+
auto_json: false,
10922+
};
10923+
10924+
create(&args, &out).unwrap();
10925+
10926+
let json = fs::read_to_string(&output_path).unwrap();
10927+
let created: ProblemJsonOutput = serde_json::from_str(&json).unwrap();
10928+
assert_eq!(created.problem_type, "GraphPartitioning");
10929+
let problem: GraphPartitioning<SimpleGraph> = serde_json::from_value(created.data).unwrap();
10930+
assert_eq!(problem.num_vertices(), 4);
10931+
10932+
let _ = fs::remove_file(output_path);
10933+
}
10934+
10935+
#[test]
10936+
fn test_create_nontautology_with_disjuncts_flag() {
10937+
use crate::dispatch::ProblemJsonOutput;
10938+
use problemreductions::models::formula::NonTautology;
10939+
10940+
let cli = Cli::try_parse_from([
10941+
"pred",
10942+
"create",
10943+
"NonTautology",
10944+
"--num-vars",
10945+
"3",
10946+
"--disjuncts",
10947+
"1,2,3;-1,-2,-3",
10948+
])
10949+
.unwrap();
10950+
let args = match cli.command {
10951+
Commands::Create(args) => args,
10952+
_ => unreachable!(),
10953+
};
10954+
10955+
let output_path = temp_output_path("non-tautology-create");
10956+
let out = OutputConfig {
10957+
output: Some(output_path.clone()),
10958+
quiet: true,
10959+
json: false,
10960+
auto_json: false,
10961+
};
10962+
10963+
create(&args, &out).unwrap();
10964+
10965+
let json = fs::read_to_string(&output_path).unwrap();
10966+
let created: ProblemJsonOutput = serde_json::from_str(&json).unwrap();
10967+
assert_eq!(created.problem_type, "NonTautology");
10968+
let problem: NonTautology = serde_json::from_value(created.data).unwrap();
10969+
assert_eq!(problem.disjuncts(), &[vec![1, 2, 3], vec![-1, -2, -3]]);
10970+
10971+
let _ = fs::remove_file(output_path);
10972+
}
10973+
1084610974
#[test]
1084710975
fn test_create_consecutive_ones_matrix_augmentation_json() {
1084810976
use crate::dispatch::ProblemJsonOutput;

0 commit comments

Comments
 (0)