use getset::CopyGetters;
use itertools::Itertools;
use crate::{
gates::{circuit::CircuitBuilderStage, flex_gate::FlexGateConfigParams},
utils::ScalarField,
virtual_region::copy_constraints::SharedCopyConstraintManager,
Context,
};
use super::SinglePhaseCoreManager;
#[derive(Clone, Debug, Default, CopyGetters)]
pub struct MultiPhaseCoreManager<F: ScalarField> {
pub phase_manager: Vec<SinglePhaseCoreManager<F>>,
pub copy_manager: SharedCopyConstraintManager<F>,
#[getset(get_copy = "pub")]
witness_gen_only: bool,
#[getset(get_copy = "pub")]
use_unknown: bool,
}
impl<F: ScalarField> MultiPhaseCoreManager<F> {
pub fn new(witness_gen_only: bool) -> Self {
let copy_manager = SharedCopyConstraintManager::default();
let phase_manager =
vec![SinglePhaseCoreManager::new(witness_gen_only, copy_manager.clone())];
Self { phase_manager, witness_gen_only, use_unknown: false, copy_manager }
}
pub fn from_stage(stage: CircuitBuilderStage) -> Self {
Self::new(stage.witness_gen_only()).unknown(stage == CircuitBuilderStage::Keygen)
}
pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager<F>) {
for pm in &mut self.phase_manager {
pm.set_copy_manager(copy_manager.clone());
}
self.copy_manager = copy_manager;
}
pub fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager<F>) -> Self {
self.set_copy_manager(copy_manager);
self
}
pub fn unknown(mut self, use_unknown: bool) -> Self {
self.use_unknown = use_unknown;
for pm in &mut self.phase_manager {
pm.use_unknown = use_unknown;
}
self
}
pub fn clear(&mut self) {
for pm in &mut self.phase_manager {
pm.clear();
}
self.copy_manager.lock().unwrap().clear();
}
pub fn main(&mut self, phase: usize) -> &mut Context<F> {
self.touch(phase);
self.phase_manager[phase].main()
}
pub fn new_thread(&mut self, phase: usize) -> &mut Context<F> {
self.touch(phase);
self.phase_manager[phase].new_thread()
}
pub fn in_phase(&mut self, phase: usize) -> &mut SinglePhaseCoreManager<F> {
self.phase_manager.get_mut(phase).unwrap()
}
pub(crate) fn touch(&mut self, phase: usize) {
while self.phase_manager.len() <= phase {
let _phase = self.phase_manager.len();
let pm = SinglePhaseCoreManager::new(self.witness_gen_only, self.copy_manager.clone())
.in_phase(_phase);
self.phase_manager.push(pm);
}
}
pub fn statistics(&self) -> GateStatistics {
let total_advice_per_phase =
self.phase_manager.iter().map(|pm| pm.total_advice()).collect::<Vec<_>>();
let total_fixed: usize = self
.copy_manager
.lock()
.unwrap()
.constant_equalities
.iter()
.map(|(c, _)| *c)
.sorted()
.dedup()
.count();
GateStatistics { total_advice_per_phase, total_fixed }
}
pub fn calculate_params(&self, k: usize, minimum_rows: Option<usize>) -> FlexGateConfigParams {
let max_rows = (1 << k) - minimum_rows.unwrap_or(0);
let stats = self.statistics();
let num_advice_per_phase = stats
.total_advice_per_phase
.iter()
.map(|count| count.div_ceil(max_rows))
.collect::<Vec<_>>();
let num_fixed = (stats.total_fixed + (1 << k) - 1) >> k;
let params = FlexGateConfigParams { num_advice_per_phase, num_fixed, k };
#[cfg(feature = "display")]
{
for (phase, num_advice) in stats.total_advice_per_phase.iter().enumerate() {
println!("Gate Chip | Phase {phase}: {num_advice} advice cells",);
}
println!("Total {} fixed cells", stats.total_fixed);
log::debug!("Auto-calculated config params:\n {params:#?}");
}
params
}
}
pub struct GateStatistics {
pub total_advice_per_phase: Vec<usize>,
pub total_fixed: usize,
}