use ark_ff::{Field, One, Zero};
use kimchi_msm::{Logup, LookupTableID};
#[derive(Copy, Clone, Debug)]
pub enum LookupMode {
Read,
Write,
}
#[derive(Clone, Debug)]
pub struct RAMLookup<T, ID: LookupTableID> {
pub(crate) table_id: ID,
pub(crate) mode: LookupMode,
pub(crate) magnitude: T,
pub(crate) value: Vec<T>,
}
impl<T, ID> RAMLookup<T, ID>
where
T: Clone
+ std::ops::Add<T, Output = T>
+ std::ops::Sub<T, Output = T>
+ std::ops::Mul<T, Output = T>
+ std::fmt::Debug
+ One
+ Zero,
ID: LookupTableID,
{
pub fn new(mode: LookupMode, table_id: ID, magnitude: T, value: &[T]) -> Self {
Self {
mode,
table_id,
magnitude,
value: value.to_vec(),
}
}
pub fn numerator(&self) -> T {
match self.mode {
LookupMode::Read => T::zero() - self.magnitude.clone(),
LookupMode::Write => self.magnitude.clone(),
}
}
pub fn into_logup(self) -> Logup<T, ID> {
Logup::new(self.table_id, self.numerator(), &self.value)
}
pub fn read_if(if_is_true: T, table_id: ID, value: Vec<T>) -> Self {
Self {
mode: LookupMode::Read,
magnitude: if_is_true,
table_id,
value,
}
}
pub fn write_if(if_is_true: T, table_id: ID, value: Vec<T>) -> Self {
Self {
mode: LookupMode::Write,
magnitude: if_is_true,
table_id,
value,
}
}
pub fn read_one(table_id: ID, value: Vec<T>) -> Self {
Self {
mode: LookupMode::Read,
magnitude: T::one(),
table_id,
value,
}
}
pub fn write_one(table_id: ID, value: Vec<T>) -> Self {
Self {
mode: LookupMode::Write,
magnitude: T::one(),
table_id,
value,
}
}
}
impl<F: std::fmt::Display + Field, ID: LookupTableID> std::fmt::Display for RAMLookup<F, ID> {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let numerator = match self.mode {
LookupMode::Read => -self.magnitude,
LookupMode::Write => self.magnitude,
};
write!(
formatter,
"numerator: {}\ntable_id: {:?}\nvalue:\n[\n",
numerator,
self.table_id.to_field::<F>()
)?;
for value in self.value.iter() {
writeln!(formatter, "\t{}", value)?;
}
write!(formatter, "]")?;
Ok(())
}
}