use crate::cnf::{Clause, CnfFormula, Literal};
const WIDTH: usize = 8;
pub(crate) fn multiplier() -> CnfFormula {
array_multiplier(WIDTH).0
}
fn array_multiplier(n: usize) -> (CnfFormula, Vec<i32>) {
let mut b = Builder::default();
let a: Vec<i32> = (0..n).map(|_| b.fresh()).collect();
let y: Vec<i32> = (0..n).map(|_| b.fresh()).collect();
let p: Vec<Vec<i32>> = (0..n)
.map(|i| (0..n).map(|j| b.and2(a[i], y[j])).collect())
.collect();
let mut acc: Vec<i32> = p[0].clone();
for i in 1..n {
let (sum, mut carry) = (b.xor2(acc[i], p[i][0]), b.and2(acc[i], p[i][0]));
acc[i] = sum;
for (j, &pij) in p[i].iter().enumerate().skip(1) {
let k = i + j;
if k < acc.len() {
let (sum, next) = (b.xor3(acc[k], pij, carry), b.maj3(acc[k], pij, carry));
acc[k] = sum;
carry = next;
} else {
let (sum, next) = (b.xor2(pij, carry), b.and2(pij, carry));
acc.push(sum);
carry = next;
}
}
acc.push(carry);
}
let formula = CnfFormula {
num_vars: b.next as u32 - 1,
clauses: b.clauses,
};
(formula, acc)
}
struct Builder {
next: i32,
clauses: Vec<Clause>,
}
impl Default for Builder {
fn default() -> Self {
Self {
next: 1,
clauses: Vec::new(),
}
}
}
impl Builder {
fn fresh(&mut self) -> i32 {
let v = self.next;
self.next += 1;
v
}
fn clause(&mut self, lits: &[i32]) {
self.clauses.push(Clause::new(
lits.iter().map(|&l| Literal::from(l)).collect(),
));
}
fn and2(&mut self, x: i32, y: i32) -> i32 {
let o = self.fresh();
self.clause(&[-o, x]);
self.clause(&[-o, y]);
self.clause(&[o, -x, -y]);
o
}
fn xor2(&mut self, x: i32, y: i32) -> i32 {
let s = self.fresh();
self.clause(&[-x, -y, -s]);
self.clause(&[x, y, -s]);
self.clause(&[x, -y, s]);
self.clause(&[-x, y, s]);
s
}
fn xor3(&mut self, x: i32, y: i32, z: i32) -> i32 {
let s = self.fresh();
for bits in 0u8..8 {
let (bx, by, bz) = (bits & 1 != 0, bits & 2 != 0, bits & 4 != 0);
let parity = bx ^ by ^ bz;
self.clause(&[
if bx { -x } else { x },
if by { -y } else { y },
if bz { -z } else { z },
if parity { s } else { -s },
]);
}
s
}
fn maj3(&mut self, x: i32, y: i32, z: i32) -> i32 {
let c = self.fresh();
for (u, v) in [(x, y), (y, z), (x, z)] {
self.clause(&[-u, -v, c]);
self.clause(&[u, v, -c]);
}
c
}
}
mod soundness;