diff --git a/src/hash_witness.rs b/src/hash_witness.rs index 9a49935f70..95e4f94104 100644 --- a/src/hash_witness.rs +++ b/src/hash_witness.rs @@ -1,145 +1,39 @@ -use std::collections::HashMap; use std::fmt::Debug; use std::marker::PhantomData; -use anyhow::{anyhow, Result}; -use once_cell::sync::OnceCell; use crate::cont::Continuation; -use crate::error::ReductionError; -use crate::field::{FWrap, LurkField}; -use crate::lurk_sym_ptr; +use crate::field::LurkField; + use crate::ptr::{ContPtr, Ptr}; -use crate::state::State; -use crate::store::{self, Store}; -use crate::tag::ExprTag; -use crate::z_ptr::{ZContPtr, ZExprPtr}; +use crate::z_ptr::ZExprPtr; -pub const MAX_CONSES_PER_REDUCTION: usize = 11; -pub const MAX_CONTS_PER_REDUCTION: usize = 2; +pub(crate) const MAX_CONSES_PER_REDUCTION: usize = 11; +pub(crate) const MAX_CONTS_PER_REDUCTION: usize = 2; #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Stub { - Dummy, - Blank, - Value(T), -} - -impl Stub { - fn is_dummy(&self) -> bool { - matches!(self, Self::Dummy) - } -} - -pub trait ContentAddressed -where - Self::ScalarPtrRepr: CAddr, -{ - type ScalarPtrRepr; - - fn preimage(&self, s: &Store) -> Result> { - self.to_scalar_ptr_repr(s) - .map(|x| x.preimage()) - .ok_or_else(|| anyhow!("failed to get preimage")) - } - fn to_scalar_ptr_repr(&self, s: &Store) -> Option; - fn to_dummy_scalar_ptr_repr() -> Option { - unimplemented!() - } -} +pub(crate) struct Stub(PhantomData); -pub trait CAddr { +pub(crate) trait CAddr { fn preimage(&self) -> Preimage; } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Cons { - pub car: Ptr, - pub cdr: Ptr, - pub cons: Ptr, +pub(crate) struct Cons { + pub(crate) car: Ptr, + pub(crate) cdr: Ptr, + pub(crate) cons: Ptr, } #[derive(Clone, Debug)] -pub struct ScalarCons { - pub car: ZExprPtr, - pub cdr: ZExprPtr, - pub cons: Option>, +pub(crate) struct ScalarCons { + pub(crate) car: ZExprPtr, + pub(crate) cdr: ZExprPtr, } #[derive(Clone, Debug)] -pub struct ScalarCont { - pub components: [F; 8], - pub cont: Option>, -} - -impl, T: CAddr> ContentAddressed - for Stub -{ - type ScalarPtrRepr = T; - - fn to_scalar_ptr_repr(&self, s: &Store) -> Option { - match self { - Stub::Dummy => C::to_dummy_scalar_ptr_repr(), - Stub::Blank => None, - Stub::Value(v) => v.to_scalar_ptr_repr(s), - } - } -} - -impl ContentAddressed for Cons { - type ScalarPtrRepr = ScalarCons; - - fn preimage(&self, s: &Store) -> Result> { - let spr = self.to_scalar_ptr_repr(s).ok_or(anyhow!("missing"))?; - Ok(spr.preimage()) - } - - fn to_scalar_ptr_repr(&self, s: &Store) -> Option { - let car = s.hash_expr(&self.car)?; - let cdr = s.hash_expr(&self.cdr)?; - let cons = Some(s.hash_expr(&self.cons)?); - Some(ScalarCons { car, cdr, cons }) - } - - fn to_dummy_scalar_ptr_repr() -> Option { - let car = ZExprPtr::from_parts(ExprTag::Nil, F::ZERO); - let cdr = ZExprPtr::from_parts(ExprTag::Nil, F::ZERO); - let cons = None; - Some(ScalarCons { car, cdr, cons }) - } -} - -impl ContentAddressed for Cont { - type ScalarPtrRepr = ScalarCont; - - fn preimage(&self, s: &Store) -> Result> { - let spr = self.to_scalar_ptr_repr(s).ok_or(anyhow!("missing"))?; - Ok(spr.preimage()) - } - - fn to_scalar_ptr_repr(&self, s: &Store) -> Option { - let cont = s.hash_cont(&self.cont_ptr)?; - let components = s.get_hash_components_cont(&self.cont_ptr).unwrap(); - Some(ScalarCont { - cont: Some(cont), - components, - }) - } - - fn to_dummy_scalar_ptr_repr() -> Option { - let cont = None; - let components = [ - F::ZERO, - F::ZERO, - F::ZERO, - F::ZERO, - F::ZERO, - F::ZERO, - F::ZERO, - F::ZERO, - ]; - Some(ScalarCont { cont, components }) - } +pub(crate) struct ScalarCont { + pub(crate) components: [F; 8], } impl CAddr for ScalarCons { @@ -160,14 +54,11 @@ impl CAddr for ScalarCont { } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Cont { - pub cont_ptr: ContPtr, - pub continuation: Continuation, +pub(crate) struct Cont { + pub(crate) cont_ptr: ContPtr, + pub(crate) continuation: Continuation, } -pub type ConsStub = Stub>; -pub type ContStub = Stub>; - #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] pub enum ConsName { #[default] @@ -203,7 +94,7 @@ pub enum ConsName { Expanded, } -pub trait HashName: Copy { +pub(crate) trait HashName: Copy { fn index(&self) -> usize; } @@ -246,15 +137,9 @@ impl HashName for ConsName { } #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Default)] -pub enum ContName { +pub(crate) enum ContName { #[default] NeverUsed, - ApplyContinuation, - LetLike, - NewerCont, - NewerCont2, - MakeThunk, - Lookup, } impl HashName for ContName { @@ -262,329 +147,19 @@ impl HashName for ContName { #[allow(clippy::match_same_arms)] match self { Self::NeverUsed => MAX_CONTS_PER_REDUCTION + 1, - Self::ApplyContinuation => 0, - Self::Lookup => 0, - Self::NewerCont => 1, - Self::NewerCont2 => 1, - Self::LetLike => 1, - Self::MakeThunk => 1, - } - } -} - -impl ConsStub { - pub fn car_cdr( - &mut self, - s: &Store, - cons: &Ptr, - ) -> Result<(Ptr, Ptr), store::Error> { - match self { - Self::Dummy => { - let (car, cdr) = Cons::get_car_cdr(s, cons)?; - - *self = Self::Value(Cons { - car, - cdr, - cons: *cons, - }); - - Ok((car, cdr)) - } - Self::Blank => unreachable!("Blank ConsStub should be used only in blank circuits."), - Self::Value(h) => Ok(h.car_cdr(cons)), - } - } - - pub fn cons(&mut self, store: &Store, car: Ptr, cdr: Ptr) -> Ptr { - match self { - Self::Dummy => { - let cons = Cons::cons(store, car, cdr); - - *self = Self::Value(Cons { car, cdr, cons }); - - cons - } - Self::Blank => unreachable!("Blank ConsStub should be used only in blank circuits."), - Self::Value(_) => Cons::cons(store, car, cdr), - } - } - pub fn strcons(&mut self, store: &Store, car: Ptr, cdr: Ptr) -> Ptr { - match self { - Self::Dummy => { - let cons = Cons::strcons(store, car, cdr); - - *self = Self::Value(Cons { car, cdr, cons }); - - cons - } - Self::Blank => unreachable!("Blank ConsStub should be used only in blank circuits."), - Self::Value(_) => Cons::strcons(store, car, cdr), } } } -impl ContStub {} - -pub type Preimage = Vec; -pub type PreimageKey = Vec>; -pub type WitnessBlock = Vec; -pub type Digest = F; -pub type HashCircuitWitnessCache = HashMap, (WitnessBlock, Digest)>; -pub type HashCircuitWitnessBlocks = Vec<(WitnessBlock, Digest)>; +pub(crate) type Preimage = Vec; +pub(crate) type WitnessBlock = Vec; +pub(crate) type Digest = F; #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct HashWitness { - pub slots: [(Name, Stub); L], +pub(crate) struct HashWitness { + pub(crate) slots: [(Name, Stub); L], _f: PhantomData, } -#[derive(Clone, Debug, PartialEq)] -pub struct CircuitHashWitness, const L: usize, F: LurkField> -{ - pub hash_witness: HashWitness, - pub names_and_ptrs: OnceCell)>>, - pub circuit_witness_blocks: OnceCell>, -} - -impl, const L: usize, F: LurkField> - From> for CircuitHashWitness -{ - fn from(hash_witness: HashWitness) -> Self { - Self { - hash_witness, - names_and_ptrs: OnceCell::new(), - circuit_witness_blocks: OnceCell::new(), - } - } -} - -pub type ConsWitness = HashWitness, MAX_CONSES_PER_REDUCTION, F>; -pub type ContWitness = HashWitness, MAX_CONTS_PER_REDUCTION, F>; - -pub type ConsCircuitWitness = CircuitHashWitness, MAX_CONSES_PER_REDUCTION, F>; -pub type ContCircuitWitness = CircuitHashWitness, MAX_CONTS_PER_REDUCTION, F>; - -impl HashWitness, MAX_CONSES_PER_REDUCTION, F> { - #[allow(dead_code)] - fn assert_specific_invariants(&self, store: &Store, state: &State) { - // Use the commented code below to search for (non-nil) duplicated conses, which could indicate that two - // different Cons are being used to reference the identical structural value. In that case, they could be - // coalesced, potentially leading to fewer slots being required. - // - // As of the initial optimization pass, Env and ExtendedClosureEnv appear to be duplicated in this way. However, - // it's not clear why that is, and coalescing them does not obviously lead to a potential savings, so we will - // leave them distinct for now. - - let mut digests = HashMap::new(); - - for (name, p) in self.slots.iter() { - if let Stub::Value(hash) = p { - if let Some(existing_name) = digests.insert(hash.cons, name) { - let nil = lurk_sym_ptr!(store, nil); - if !store.ptr_eq(&hash.cons, &nil).unwrap() { - use crate::writer::Write; - let cons = hash.cons.fmt_to_string(store, state); - tracing::debug!( - "{:?} {:?} {:?} {:?}", - hash.cons, - cons, - name, - existing_name - ); - panic!("duplicate"); - } - } - }; - } - } -} - -impl< - Name: HashName + Default + Copy + Eq + Debug, - T: Copy, - const MAX_T_PER_REDUCTION: usize, - F: LurkField, - > HashWitness -{ - pub fn new_from_stub(stub: Stub) -> Self { - Self { - slots: [(Name::default(), stub); MAX_T_PER_REDUCTION], - _f: Default::default(), - } - } - - pub fn new_dummy() -> Self { - Self::new_from_stub(Stub::Dummy) - } - - pub fn get_assigned_slot(&mut self, name: Name) -> &mut Stub { - let i = name.index(); - let (slot_name, p) = self.slots[i]; - if p.is_dummy() { - self.slots[i].0 = name; - return &mut self.slots[i].1; - } - if slot_name == name { - &mut self.slots[i].1 - } else { - panic!( - "double booked: found {:?} when getting {:?}", - &slot_name, &name - ); - } - } - - pub fn assert_invariants(&self, _store: &Store) { - // TODO: Figure out how to make this work. - // self.assert_specific_invariants(store); - assert!(self.stubs_used_count() <= MAX_T_PER_REDUCTION); - } - - fn all_stubs(&self) -> Vec> { - self.slots.iter().map(|x| x.1).collect() - } - - pub fn stubs_used_count(&self) -> usize { - self.all_stubs().iter().filter(|c| !c.is_dummy()).count() - } -} - -impl ConsWitness { - pub fn car_cdr_named( - &mut self, - name: ConsName, - store: &Store, - cons: &Ptr, - ) -> Result<(Ptr, Ptr), ReductionError> { - if !matches!(cons.tag, ExprTag::Cons | ExprTag::Nil) { - return Err(ReductionError::CarCdrType(name)); - }; - self.get_assigned_slot(name) - .car_cdr(store, cons) - .map_err(|e| e.into()) - } - - pub fn cons_named( - &mut self, - name: ConsName, - store: &Store, - car: Ptr, - cdr: Ptr, - ) -> Ptr { - self.get_assigned_slot(name).cons(store, car, cdr) - } - - pub fn strcons_named( - &mut self, - name: ConsName, - store: &Store, - car: Ptr, - cdr: Ptr, - ) -> Ptr { - self.get_assigned_slot(name).strcons(store, car, cdr) - } - - pub fn car_cdr_mut_named( - &mut self, - name: ConsName, - store: &Store, - cons: &Ptr, - ) -> Result<(Ptr, Ptr), store::Error> { - self.get_assigned_slot(name).car_cdr(store, cons) - } - - pub fn extend_named( - &mut self, - name: ConsName, - env: Ptr, - var: Ptr, - val: Ptr, - store: &Store, - ) -> Ptr { - let binding = self.cons_named(ConsName::Binding, store, var, val); - - self.cons_named(name, store, binding, env) - } -} - -impl Cons { - fn cons(store: &Store, car: Ptr, cdr: Ptr) -> Ptr { - store.cons(car, cdr) - } - - fn strcons(store: &Store, car: Ptr, cdr: Ptr) -> Ptr { - store.strcons(car, cdr) - } - - fn car_cdr(&self, cons: &Ptr) -> (Ptr, Ptr) { - assert_eq!(cons, &self.cons, "wrong cons found when destructuring"); - - (self.car, self.cdr) - } - - fn get_car_cdr(s: &Store, cons: &Ptr) -> Result<(Ptr, Ptr), store::Error> { - s.car_cdr(cons) - } -} - -impl ContWitness { - pub fn fetch_named_cont( - &mut self, - name: ContName, - store: &Store, - cont: &ContPtr, - ) -> Option> { - self.get_assigned_slot(name).fetch_cont(store, cont) - } - - pub fn intern_named_cont( - &mut self, - name: ContName, - store: &Store, - continuation: Continuation, - ) -> ContPtr { - self.get_assigned_slot(name) - .intern_cont(store, continuation) - } -} - -impl ContStub { - pub fn fetch_cont(&mut self, store: &Store, cont: &ContPtr) -> Option> { - match self { - Self::Dummy => { - let continuation = store.fetch_cont(cont)?; - // tracing::debug!("overwriting dummy {:?} {:?}", continuation, store.hash_cont(&cont)); - *self = Self::Value(Cont { - cont_ptr: *cont, - continuation, - }); - - Some(continuation) - } - Self::Blank => unreachable!("Blank ContStub should be used only in blank circuits."), - Self::Value(h) => Some(h.fetch_cont(cont)), - } - } - pub fn intern_cont(&mut self, store: &Store, continuation: Continuation) -> ContPtr { - match self { - Self::Dummy => { - let cont_ptr = continuation.intern_aux(store); - *self = Self::Value(Cont { - cont_ptr, - continuation, - }); - cont_ptr - } - Self::Blank => unreachable!("Blank ContStub should be used only in blank circuits."), - Self::Value(h) => h.cont_ptr, - } - } -} - -impl Cont { - fn fetch_cont(&mut self, cont: &ContPtr) -> Continuation { - assert_eq!(cont, &self.cont_ptr); - - self.continuation - } -} +pub(crate) type ConsWitness = HashWitness, MAX_CONSES_PER_REDUCTION, F>; +pub(crate) type ContWitness = HashWitness, MAX_CONTS_PER_REDUCTION, F>; \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 6ed32b8474..e79cc12308 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ pub mod eval; pub mod expr; pub mod field; pub mod hash; -pub mod hash_witness; +mod hash_witness; pub mod lem; mod num; pub mod package;