use field_cat::Field;
use crate::error::Error;
use crate::expr::Expression;
use crate::wire::Wire;
#[derive(Debug, Clone)]
pub struct Constraint<F: Field> {
expression: Expression<F>,
}
impl<F: Field> Constraint<F> {
#[must_use]
pub fn new(expression: Expression<F>) -> Self {
Self { expression }
}
#[must_use]
pub fn expression(&self) -> &Expression<F> {
&self.expression
}
pub fn is_satisfied(
&self,
assignment: &dyn Fn(Wire) -> Result<F, Error>,
) -> Result<bool, Error> {
self.expression.evaluate(assignment).map(|v| v == F::zero())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CopyConstraint {
left: Wire,
right: Wire,
}
impl CopyConstraint {
#[must_use]
pub fn new(left: Wire, right: Wire) -> Self {
Self { left, right }
}
#[must_use]
pub fn left(&self) -> Wire {
self.left
}
#[must_use]
pub fn right(&self) -> Wire {
self.right
}
pub fn is_satisfied_with<F: Field>(
&self,
assignment: &dyn Fn(Wire) -> Result<F, Error>,
) -> Result<bool, Error> {
let l = assignment(self.left)?;
let r = assignment(self.right)?;
Ok(l == r)
}
}
#[derive(Debug, Clone)]
pub struct ConstraintSet<F: Field> {
constraints: Vec<Constraint<F>>,
copy_constraints: Vec<CopyConstraint>,
}
impl<F: Field> ConstraintSet<F> {
#[must_use]
pub fn empty() -> Self {
Self {
constraints: Vec::new(),
copy_constraints: Vec::new(),
}
}
#[must_use]
pub fn with_constraint(self, c: Constraint<F>) -> Self {
Self {
constraints: self
.constraints
.into_iter()
.chain(core::iter::once(c))
.collect(),
copy_constraints: self.copy_constraints,
}
}
#[must_use]
pub fn with_copy(self, cc: CopyConstraint) -> Self {
Self {
constraints: self.constraints,
copy_constraints: self
.copy_constraints
.into_iter()
.chain(core::iter::once(cc))
.collect(),
}
}
#[must_use]
pub fn merge(self, other: Self) -> Self {
Self {
constraints: self
.constraints
.into_iter()
.chain(other.constraints)
.collect(),
copy_constraints: self
.copy_constraints
.into_iter()
.chain(other.copy_constraints)
.collect(),
}
}
#[must_use]
pub fn constraints(&self) -> &[Constraint<F>] {
&self.constraints
}
#[must_use]
pub fn copy_constraints(&self) -> &[CopyConstraint] {
&self.copy_constraints
}
pub fn is_satisfied(
&self,
assignment: &dyn Fn(Wire) -> Result<F, Error>,
) -> Result<bool, Error> {
let polys_ok = self.constraints.iter().try_fold(true, |acc, c| {
c.is_satisfied(assignment).map(|ok| acc && ok)
})?;
let copies_ok =
self.copy_constraints
.iter()
.try_fold(true, |acc, cc| -> Result<bool, Error> {
let l = assignment(cc.left())?;
let r = assignment(cc.right())?;
Ok(acc && l == r)
})?;
Ok(polys_ok && copies_ok)
}
}