1use crate::models::formula::{Assignment, BooleanExpr, Circuit, CircuitSAT};
11use crate::models::misc::Factoring;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14#[derive(Debug, Clone)]
22pub struct ReductionFactoringToCircuit {
23 target: CircuitSAT,
25 p_vars: Vec<String>,
27 q_vars: Vec<String>,
29 m_vars: Vec<String>,
31}
32
33impl ReductionResult for ReductionFactoringToCircuit {
34 type Source = Factoring;
35 type Target = CircuitSAT;
36
37 fn target_problem(&self) -> &Self::Target {
38 &self.target
39 }
40
41 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
46 let var_names = self.target.variable_names();
47
48 let var_map: std::collections::HashMap<&str, usize> = var_names
50 .iter()
51 .enumerate()
52 .map(|(i, name)| (name.as_str(), target_solution.get(i).copied().unwrap_or(0)))
53 .collect();
54
55 let p_bits: Vec<usize> = self
57 .p_vars
58 .iter()
59 .map(|name| *var_map.get(name.as_str()).unwrap_or(&0))
60 .collect();
61
62 let q_bits: Vec<usize> = self
64 .q_vars
65 .iter()
66 .map(|name| *var_map.get(name.as_str()).unwrap_or(&0))
67 .collect();
68
69 let mut result = p_bits;
71 result.extend(q_bits);
72 result
73 }
74}
75
76impl ReductionFactoringToCircuit {
77 pub fn p_vars(&self) -> &[String] {
79 &self.p_vars
80 }
81
82 pub fn q_vars(&self) -> &[String] {
84 &self.q_vars
85 }
86
87 pub fn m_vars(&self) -> &[String] {
89 &self.m_vars
90 }
91}
92
93fn read_bit(n: u64, i: usize) -> bool {
95 if i == 0 || i > 64 {
96 false
97 } else {
98 ((n >> (i - 1)) & 1) == 1
99 }
100}
101
102fn build_multiplier_cell(
108 s_name: &str,
109 c_name: &str,
110 p_name: &str,
111 q_name: &str,
112 s_pre: &BooleanExpr,
113 c_pre: &BooleanExpr,
114 cell_id: &str,
115) -> (Vec<Assignment>, Vec<String>) {
116 let a_name = format!("a_{}", cell_id);
118 let a_xor_s_name = format!("axs_{}", cell_id);
119 let a_xor_s_and_c_name = format!("axsc_{}", cell_id);
120 let a_and_s_name = format!("as_{}", cell_id);
121
122 let p = BooleanExpr::var(p_name);
123 let q = BooleanExpr::var(q_name);
124 let a = BooleanExpr::var(&a_name);
125 let a_xor_s = BooleanExpr::var(&a_xor_s_name);
126
127 let assign_a = Assignment::new(vec![a_name.clone()], BooleanExpr::and(vec![p, q]));
130
131 let assign_a_xor_s = Assignment::new(
133 vec![a_xor_s_name.clone()],
134 BooleanExpr::xor(vec![a.clone(), s_pre.clone()]),
135 );
136
137 let assign_s = Assignment::new(
139 vec![s_name.to_string()],
140 BooleanExpr::xor(vec![a_xor_s.clone(), c_pre.clone()]),
141 );
142
143 let assign_a_xor_s_and_c = Assignment::new(
145 vec![a_xor_s_and_c_name.clone()],
146 BooleanExpr::and(vec![a_xor_s, c_pre.clone()]),
147 );
148
149 let assign_a_and_s = Assignment::new(
151 vec![a_and_s_name.clone()],
152 BooleanExpr::and(vec![a, s_pre.clone()]),
153 );
154
155 let assign_c = Assignment::new(
157 vec![c_name.to_string()],
158 BooleanExpr::or(vec![
159 BooleanExpr::var(&a_xor_s_and_c_name),
160 BooleanExpr::var(&a_and_s_name),
161 ]),
162 );
163
164 let assignments = vec![
165 assign_a,
166 assign_a_xor_s,
167 assign_s,
168 assign_a_xor_s_and_c,
169 assign_a_and_s,
170 assign_c,
171 ];
172
173 let ancillas = vec![a_name, a_xor_s_name, a_xor_s_and_c_name, a_and_s_name];
174
175 (assignments, ancillas)
176}
177
178#[reduction(overhead = {
179 num_variables = "6 * num_bits_first * num_bits_second + num_bits_first + num_bits_second",
180 num_assignments = "6 * num_bits_first * num_bits_second + num_bits_first + num_bits_second",
181})]
182impl ReduceTo<CircuitSAT> for Factoring {
183 type Result = ReductionFactoringToCircuit;
184
185 fn reduce_to(&self) -> Self::Result {
186 let n1 = self.m(); let n2 = self.n(); let target = self.target();
189
190 let p_vars: Vec<String> = (1..=n1).map(|i| format!("p{}", i)).collect();
192 let q_vars: Vec<String> = (1..=n2).map(|i| format!("q{}", i)).collect();
193
194 let mut assignments = Vec::new();
196 let mut m_vars = Vec::new();
197
198 let mut s_pre: Vec<BooleanExpr> = (0..=n2).map(|_| BooleanExpr::constant(false)).collect();
201
202 for i in 1..=n1 {
204 let mut c_pre = BooleanExpr::constant(false);
206
207 for j in 1..=n2 {
208 let c_name = format!("c{}_{}", i, j);
210 let s_name = format!("s{}_{}", i, j);
211
212 let cell_id = format!("{}_{}", i, j);
214 let (cell_assignments, _ancillas) = build_multiplier_cell(
215 &s_name,
216 &c_name,
217 &p_vars[i - 1],
218 &q_vars[j - 1],
219 &s_pre[j], &c_pre,
221 &cell_id,
222 );
223
224 assignments.extend(cell_assignments);
225
226 c_pre = BooleanExpr::var(&c_name);
228
229 s_pre[j - 1] = BooleanExpr::var(&s_name);
232 }
233
234 s_pre[n2] = c_pre;
236
237 m_vars.push(format!("s{}_{}", i, 1));
239 }
240
241 for j in 2..=n2 {
243 m_vars.push(format!("s{}_{}", n1, j));
244 }
245 m_vars.push(format!("c{}_{}", n1, n2));
247
248 for (i, m_var) in m_vars.iter().enumerate() {
250 let target_bit = read_bit(target, i + 1);
251 assignments.push(Assignment::new(
252 vec![m_var.clone()],
253 BooleanExpr::constant(target_bit),
254 ));
255 }
256
257 let circuit = Circuit::new(assignments);
259 let circuit_sat = CircuitSAT::new(circuit);
260
261 ReductionFactoringToCircuit {
262 target: circuit_sat,
263 p_vars,
264 q_vars,
265 m_vars,
266 }
267 }
268}
269
270#[cfg(test)]
271#[path = "../unit_tests/rules/factoring_circuit.rs"]
272mod tests;