use crate::field::Goldilocks;
use crate::fwht::FWHT;
use crate::signal::SpectralSignal;
pub struct SpectralConstraint;
impl SpectralConstraint {
pub fn verify_and(a: &SpectralSignal, b: &SpectralSignal, c: &SpectralSignal) -> bool {
let fa = FWHT::fwht(a);
let fb = FWHT::fwht(b);
let fc = FWHT::fwht(c);
let mut f_fa = fa.values.clone();
FWHT::transform(&mut f_fa);
let mut f_fb = fb.values.clone();
FWHT::transform(&mut f_fb);
let mut f_fc: Vec<Goldilocks> = f_fa
.iter()
.zip(f_fb.iter())
.map(|(&x, &y)| x.mul(y))
.collect();
FWHT::transform(&mut f_fc);
let n_inv = Goldilocks::from_i64(fa.values.len() as i64).inv();
let nn_inv = n_inv.mul(n_inv);
for i in 0..fc.values.len() {
let lhs = fc.values[i];
let rhs = f_fc[i].mul(nn_inv);
if lhs != rhs {
return false;
}
}
true
}
pub fn verify_xor(a: &SpectralSignal, b: &SpectralSignal, c: &SpectralSignal) -> bool {
let fa = FWHT::fwht(a);
let fb = FWHT::fwht(b);
let fc = FWHT::fwht(c);
let mut f_fa = fa.values.clone();
FWHT::transform(&mut f_fa);
let mut f_fb = fb.values.clone();
FWHT::transform(&mut f_fb);
let mut f_fc_and: Vec<Goldilocks> = f_fa
.iter()
.zip(f_fb.iter())
.map(|(&x, &y)| x.mul(y))
.collect();
FWHT::transform(&mut f_fc_and);
let n_inv = Goldilocks::from_i64(fa.values.len() as i64).inv();
let nn_inv = n_inv.mul(n_inv);
let two = Goldilocks::from_i64(2);
for i in 0..fc.values.len() {
let term_and = f_fc_and[i].mul(nn_inv);
let lhs = fc.values[i];
let rhs = fa.values[i].add(fb.values[i]).sub(two.mul(term_and));
if lhs != rhs {
return false;
}
}
true
}
pub fn verify_selection(
sel: &SpectralSignal,
a: &SpectralSignal,
b: &SpectralSignal,
out: &SpectralSignal,
sel_and_a: &SpectralSignal,
nsel_and_b: &SpectralSignal,
) -> bool {
if !Self::verify_and(sel, a, sel_and_a) {
return false;
}
let val_nsel: Vec<i64> = sel.values.iter().map(|s| 1 - s).collect();
if !Self::verify_and(&SpectralSignal::new(val_nsel), b, nsel_and_b) {
return false;
}
let f_out = FWHT::fwht(out);
let f_p1 = FWHT::fwht(sel_and_a);
let f_p2 = FWHT::fwht(nsel_and_b);
for i in 0..f_out.values.len() {
if f_out.values[i] != f_p1.values[i].add(f_p2.values[i]) {
return false;
}
}
true
}
pub fn verify_boolean(a: &SpectralSignal) -> bool {
Self::verify_and(a, a, a)
}
pub fn enforce_spectral_booleanity(signal: &SpectralSignal) -> bool {
let squared = signal.mul(signal);
for i in 0..signal.values.len() {
let v = signal.values[i];
let v_sq = squared.values[i];
if v != v_sq {
return false;
}
}
true
}
}
#[deprecated(note = "Use SpectralConstraint instead")]
pub type SpectralGate = SpectralConstraint;