use core::{
fmt::Debug,
iter::{Product, Sum},
ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use std::{
hash::{Hash, Hasher},
ptr,
sync::Arc,
};
use p3_field::{Algebra, Field, PrimeCharacteristicRing};
use serde::{Deserialize, Serialize};
use super::{dag::SymbolicExpressionNode, symbolic_variable::SymbolicVariable};
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "F: Field")]
pub enum SymbolicExpression<F> {
Variable(SymbolicVariable<F>),
IsFirstRow,
IsLastRow,
IsTransition,
Constant(F),
Add {
x: Arc<Self>,
y: Arc<Self>,
degree_multiple: usize,
},
Sub {
x: Arc<Self>,
y: Arc<Self>,
degree_multiple: usize,
},
Neg {
x: Arc<Self>,
degree_multiple: usize,
},
Mul {
x: Arc<Self>,
y: Arc<Self>,
degree_multiple: usize,
},
}
impl<F: Field> Hash for SymbolicExpression<F> {
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Self::Variable(v) => v.hash(state),
Self::IsFirstRow => {} Self::IsLastRow => {} Self::IsTransition => {} Self::Constant(f) => f.hash(state),
Self::Add { x, y, .. } => {
ptr::hash(&**x, state);
ptr::hash(&**y, state);
}
Self::Sub { x, y, .. } => {
ptr::hash(&**x, state);
ptr::hash(&**y, state);
}
Self::Neg { x, .. } => {
ptr::hash(&**x, state);
}
Self::Mul { x, y, .. } => {
ptr::hash(&**x, state);
ptr::hash(&**y, state);
}
}
}
}
impl<F: Field> PartialEq for SymbolicExpression<F> {
fn eq(&self, other: &Self) -> bool {
if std::mem::discriminant(self) != std::mem::discriminant(other) {
return false;
}
match (self, other) {
(Self::Variable(v1), Self::Variable(v2)) => v1 == v2,
(Self::IsFirstRow, Self::IsFirstRow) => true,
(Self::IsLastRow, Self::IsLastRow) => true,
(Self::IsTransition, Self::IsTransition) => true,
(Self::Constant(c1), Self::Constant(c2)) => c1 == c2,
(Self::Add { x: x1, y: y1, .. }, Self::Add { x: x2, y: y2, .. }) => {
Arc::ptr_eq(x1, x2) && Arc::ptr_eq(y1, y2)
}
(Self::Sub { x: x1, y: y1, .. }, Self::Sub { x: x2, y: y2, .. }) => {
Arc::ptr_eq(x1, x2) && Arc::ptr_eq(y1, y2)
}
(Self::Neg { x: x1, .. }, Self::Neg { x: x2, .. }) => Arc::ptr_eq(x1, x2),
(Self::Mul { x: x1, y: y1, .. }, Self::Mul { x: x2, y: y2, .. }) => {
Arc::ptr_eq(x1, x2) && Arc::ptr_eq(y1, y2)
}
_ => false,
}
}
}
impl<F: Field> Eq for SymbolicExpression<F> {}
impl<F: Field> SymbolicExpression<F> {
pub const fn degree_multiple(&self) -> usize {
match self {
SymbolicExpression::Variable(v) => v.degree_multiple(),
SymbolicExpression::IsFirstRow => 1,
SymbolicExpression::IsLastRow => 1,
SymbolicExpression::IsTransition => 1,
SymbolicExpression::Constant(_) => 0,
SymbolicExpression::Add {
degree_multiple, ..
} => *degree_multiple,
SymbolicExpression::Sub {
degree_multiple, ..
} => *degree_multiple,
SymbolicExpression::Neg {
degree_multiple, ..
} => *degree_multiple,
SymbolicExpression::Mul {
degree_multiple, ..
} => *degree_multiple,
}
}
}
impl<F: Field> Default for SymbolicExpression<F> {
fn default() -> Self {
Self::Constant(F::ZERO)
}
}
impl<F: Field> From<F> for SymbolicExpression<F> {
fn from(value: F) -> Self {
Self::Constant(value)
}
}
impl<F: Field> PrimeCharacteristicRing for SymbolicExpression<F> {
type PrimeSubfield = F::PrimeSubfield;
const ZERO: Self = Self::Constant(F::ZERO);
const ONE: Self = Self::Constant(F::ONE);
const TWO: Self = Self::Constant(F::TWO);
const NEG_ONE: Self = Self::Constant(F::NEG_ONE);
#[inline]
fn from_prime_subfield(f: Self::PrimeSubfield) -> Self {
F::from_prime_subfield(f).into()
}
}
impl<F: Field> Add for SymbolicExpression<F> {
type Output = Self;
fn add(self, rhs: Self) -> Self {
let degree_multiple = self.degree_multiple().max(rhs.degree_multiple());
Self::Add {
x: Arc::new(self),
y: Arc::new(rhs),
degree_multiple,
}
}
}
impl<F: Field> Add<F> for SymbolicExpression<F> {
type Output = Self;
fn add(self, rhs: F) -> Self {
self + Self::from(rhs)
}
}
impl<F: Field> AddAssign for SymbolicExpression<F> {
fn add_assign(&mut self, rhs: Self) {
*self = self.clone() + rhs;
}
}
impl<F: Field> AddAssign<SymbolicVariable<F>> for SymbolicExpression<F> {
fn add_assign(&mut self, rhs: SymbolicVariable<F>) {
*self += SymbolicExpression::from(rhs);
}
}
impl<F: Field> AddAssign<F> for SymbolicExpression<F> {
fn add_assign(&mut self, rhs: F) {
*self += Self::from(rhs);
}
}
impl<F: Field> Sum for SymbolicExpression<F> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|x, y| x + y).unwrap_or(Self::ZERO)
}
}
impl<F: Field> Sum<F> for SymbolicExpression<F> {
fn sum<I: Iterator<Item = F>>(iter: I) -> Self {
iter.map(|x| Self::from(x)).sum()
}
}
impl<F: Field> Sub for SymbolicExpression<F> {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
let degree_multiple = self.degree_multiple().max(rhs.degree_multiple());
Self::Sub {
x: Arc::new(self),
y: Arc::new(rhs),
degree_multiple,
}
}
}
impl<F: Field> Sub<F> for SymbolicExpression<F> {
type Output = Self;
fn sub(self, rhs: F) -> Self {
self - Self::from(rhs)
}
}
impl<F: Field> SubAssign for SymbolicExpression<F> {
fn sub_assign(&mut self, rhs: Self) {
*self = self.clone() - rhs;
}
}
impl<F: Field> SubAssign<F> for SymbolicExpression<F> {
fn sub_assign(&mut self, rhs: F) {
*self -= Self::from(rhs);
}
}
impl<F: Field> SubAssign<SymbolicVariable<F>> for SymbolicExpression<F> {
fn sub_assign(&mut self, rhs: SymbolicVariable<F>) {
*self -= SymbolicExpression::from(rhs);
}
}
impl<F: Field> Neg for SymbolicExpression<F> {
type Output = Self;
fn neg(self) -> Self {
let degree_multiple = self.degree_multiple();
Self::Neg {
x: Arc::new(self),
degree_multiple,
}
}
}
impl<F: Field> Mul for SymbolicExpression<F> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
#[allow(clippy::suspicious_arithmetic_impl)]
let degree_multiple = self.degree_multiple() + rhs.degree_multiple();
Self::Mul {
x: Arc::new(self),
y: Arc::new(rhs),
degree_multiple,
}
}
}
impl<F: Field> Mul<F> for SymbolicExpression<F> {
type Output = Self;
fn mul(self, rhs: F) -> Self {
self * Self::from(rhs)
}
}
impl<F: Field> MulAssign for SymbolicExpression<F> {
fn mul_assign(&mut self, rhs: Self) {
*self = self.clone() * rhs;
}
}
impl<F: Field> MulAssign<F> for SymbolicExpression<F> {
fn mul_assign(&mut self, rhs: F) {
*self *= Self::from(rhs);
}
}
impl<F: Field> MulAssign<SymbolicVariable<F>> for SymbolicExpression<F> {
fn mul_assign(&mut self, rhs: SymbolicVariable<F>) {
*self *= SymbolicExpression::from(rhs);
}
}
impl<F: Field> Product for SymbolicExpression<F> {
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.reduce(|x, y| x * y).unwrap_or(Self::ONE)
}
}
impl<F: Field> Product<F> for SymbolicExpression<F> {
fn product<I: Iterator<Item = F>>(iter: I) -> Self {
iter.map(|x| Self::from(x)).product()
}
}
impl<F: Field> Algebra<F> for SymbolicExpression<F> {}
impl<F: Field> Algebra<SymbolicVariable<F>> for SymbolicExpression<F> {}
pub trait SymbolicEvaluator<F, E>
where
F: Field,
E: Add<E, Output = E> + Sub<E, Output = E> + Mul<E, Output = E> + Neg<Output = E>,
{
fn eval_const(&self, c: F) -> E;
fn eval_var(&self, symbolic_var: SymbolicVariable<F>) -> E;
fn eval_is_first_row(&self) -> E;
fn eval_is_last_row(&self) -> E;
fn eval_is_transition(&self) -> E;
fn eval_expr(&self, symbolic_expr: &SymbolicExpression<F>) -> E {
match symbolic_expr {
SymbolicExpression::Variable(var) => self.eval_var(*var),
SymbolicExpression::Constant(c) => self.eval_const(*c),
SymbolicExpression::Add { x, y, .. } => self.eval_expr(x) + self.eval_expr(y),
SymbolicExpression::Sub { x, y, .. } => self.eval_expr(x) - self.eval_expr(y),
SymbolicExpression::Neg { x, .. } => -self.eval_expr(x),
SymbolicExpression::Mul { x, y, .. } => self.eval_expr(x) * self.eval_expr(y),
SymbolicExpression::IsFirstRow => self.eval_is_first_row(),
SymbolicExpression::IsLastRow => self.eval_is_last_row(),
SymbolicExpression::IsTransition => self.eval_is_transition(),
}
}
fn eval_nodes(&self, nodes: &[SymbolicExpressionNode<F>]) -> Vec<E>
where
E: Clone,
{
let mut exprs: Vec<E> = Vec::with_capacity(nodes.len());
for node in nodes {
let expr = match *node {
SymbolicExpressionNode::Variable(var) => self.eval_var(var),
SymbolicExpressionNode::Constant(c) => self.eval_const(c),
SymbolicExpressionNode::Add {
left_idx,
right_idx,
..
} => exprs[left_idx].clone() + exprs[right_idx].clone(),
SymbolicExpressionNode::Sub {
left_idx,
right_idx,
..
} => exprs[left_idx].clone() - exprs[right_idx].clone(),
SymbolicExpressionNode::Neg { idx, .. } => -exprs[idx].clone(),
SymbolicExpressionNode::Mul {
left_idx,
right_idx,
..
} => exprs[left_idx].clone() * exprs[right_idx].clone(),
SymbolicExpressionNode::IsFirstRow => self.eval_is_first_row(),
SymbolicExpressionNode::IsLastRow => self.eval_is_last_row(),
SymbolicExpressionNode::IsTransition => self.eval_is_transition(),
};
exprs.push(expr);
}
exprs
}
}