problemreductions/rules/
naesatisfiability_setsplitting.rs1use crate::models::formula::NAESatisfiability;
10use crate::models::set::SetSplitting;
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13
14#[derive(Debug, Clone)]
15pub struct ReductionNAESATToSetSplitting {
16 target: SetSplitting,
17 num_source_variables: usize,
18}
19
20impl ReductionResult for ReductionNAESATToSetSplitting {
21 type Source = NAESatisfiability;
22 type Target = SetSplitting;
23
24 fn target_problem(&self) -> &SetSplitting {
25 &self.target
26 }
27
28 fn extract_solution(
29 &self,
30 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
31 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
32 crate::rules::traits::validate_target_witness(
33 self.target_problem(),
34 target_solution,
35 |value| value.0,
36 "target witness does not satisfy the target problem",
37 )?;
38
39 Ok(target_solution[..self.num_source_variables].to_vec())
40 }
41}
42
43fn literal_element_index(lit: i64, num_vars: usize) -> usize {
44 let var_index = lit.unsigned_abs() as usize - 1;
45 if lit > 0 {
46 var_index
47 } else {
48 num_vars + var_index
49 }
50}
51
52#[crate::aggregate_reduction(identity)]
53impl crate::rules::AggregateReductionResult for ReductionNAESATToSetSplitting {}
54
55#[reduction(
56 transform = exact {
57 universe_size = "2 * num_vars",
58 num_subsets = "num_vars + num_clauses",
59 }
60)]
61impl ReduceTo<SetSplitting> for NAESatisfiability {
62 type Result = ReductionNAESATToSetSplitting;
63
64 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
65 let num_vars = self.num_vars();
66 let mut subsets = Vec::with_capacity(num_vars + self.num_clauses());
67
68 for var_index in 0..num_vars {
69 subsets.push(vec![var_index, num_vars + var_index]);
70 }
71
72 for clause in self.clauses() {
73 subsets.push(
74 clause
75 .literals
76 .iter()
77 .map(|&lit| literal_element_index(lit, num_vars))
78 .collect(),
79 );
80 }
81
82 Ok(ReductionNAESATToSetSplitting {
83 target: SetSplitting::new(2 * num_vars, subsets),
84 num_source_variables: num_vars,
85 })
86 }
87}
88
89#[cfg(feature = "example-db")]
90pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
91 use crate::export::SolutionPair;
92 use crate::models::formula::CNFClause;
93
94 vec![crate::example_db::specs::RuleExampleSpec {
95 id: "naesatisfiability_to_setsplitting",
96 build: || {
97 crate::example_db::specs::rule_example_with_witness::<_, SetSplitting>(
98 NAESatisfiability::new(
99 3,
100 vec![
101 CNFClause::new(vec![1, -2, 3]),
102 CNFClause::new(vec![-1, 2, -3]),
103 ],
104 ),
105 SolutionPair {
106 source_config: serde_json::json!(vec![true, true, true]),
107 target_config: serde_json::json!(vec![true, true, true, false, false, false]),
108 },
109 )
110 },
111 }]
112}
113
114#[cfg(test)]
115#[path = "../unit_tests/rules/naesatisfiability_setsplitting.rs"]
116mod tests;