halo2_base/gates/flex_gate/threads/
multi_phase.rs1use getset::CopyGetters;
2use itertools::Itertools;
3
4use crate::{
5 gates::{circuit::CircuitBuilderStage, flex_gate::FlexGateConfigParams},
6 utils::ScalarField,
7 virtual_region::copy_constraints::SharedCopyConstraintManager,
8 Context,
9};
10
11use super::SinglePhaseCoreManager;
12
13#[derive(Clone, Debug, Default, CopyGetters)]
15pub struct MultiPhaseCoreManager<F: ScalarField> {
16 pub phase_manager: Vec<SinglePhaseCoreManager<F>>,
18 pub copy_manager: SharedCopyConstraintManager<F>,
20 #[getset(get_copy = "pub")]
22 witness_gen_only: bool,
23 #[getset(get_copy = "pub")]
25 use_unknown: bool,
26}
27
28impl<F: ScalarField> MultiPhaseCoreManager<F> {
29 pub fn new(witness_gen_only: bool) -> Self {
36 let copy_manager = SharedCopyConstraintManager::default();
37 let phase_manager =
38 vec![SinglePhaseCoreManager::new(witness_gen_only, copy_manager.clone())];
39 Self { phase_manager, witness_gen_only, use_unknown: false, copy_manager }
40 }
41
42 pub fn from_stage(stage: CircuitBuilderStage) -> Self {
44 Self::new(stage.witness_gen_only()).unknown(stage == CircuitBuilderStage::Keygen)
45 }
46
47 pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager<F>) {
49 for pm in &mut self.phase_manager {
50 pm.set_copy_manager(copy_manager.clone());
51 }
52 self.copy_manager = copy_manager;
53 }
54
55 pub fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager<F>) -> Self {
57 self.set_copy_manager(copy_manager);
58 self
59 }
60
61 pub fn unknown(mut self, use_unknown: bool) -> Self {
64 self.use_unknown = use_unknown;
65 for pm in &mut self.phase_manager {
66 pm.use_unknown = use_unknown;
67 }
68 self
69 }
70
71 pub fn clear(&mut self) {
73 for pm in &mut self.phase_manager {
74 pm.clear();
75 }
76 self.copy_manager.lock().unwrap().clear();
77 }
78
79 pub fn main(&mut self, phase: usize) -> &mut Context<F> {
82 self.touch(phase);
83 self.phase_manager[phase].main()
84 }
85
86 pub fn new_thread(&mut self, phase: usize) -> &mut Context<F> {
89 self.touch(phase);
90 self.phase_manager[phase].new_thread()
91 }
92
93 pub fn in_phase(&mut self, phase: usize) -> &mut SinglePhaseCoreManager<F> {
95 self.phase_manager.get_mut(phase).unwrap()
96 }
97
98 pub(crate) fn touch(&mut self, phase: usize) {
100 while self.phase_manager.len() <= phase {
101 let _phase = self.phase_manager.len();
102 let pm = SinglePhaseCoreManager::new(self.witness_gen_only, self.copy_manager.clone())
103 .in_phase(_phase);
104 self.phase_manager.push(pm);
105 }
106 }
107
108 pub fn statistics(&self) -> GateStatistics {
110 let total_advice_per_phase =
111 self.phase_manager.iter().map(|pm| pm.total_advice()).collect::<Vec<_>>();
112
113 let total_fixed: usize = self
114 .copy_manager
115 .lock()
116 .unwrap()
117 .constant_equalities
118 .iter()
119 .map(|(c, _)| *c)
120 .sorted()
121 .dedup()
122 .count();
123
124 GateStatistics { total_advice_per_phase, total_fixed }
125 }
126
127 pub fn calculate_params(&self, k: usize, minimum_rows: Option<usize>) -> FlexGateConfigParams {
132 let max_rows = (1 << k) - minimum_rows.unwrap_or(0);
133 let stats = self.statistics();
134 let num_advice_per_phase = stats
137 .total_advice_per_phase
138 .iter()
139 .map(|count| count.div_ceil(max_rows))
140 .collect::<Vec<_>>();
141 let num_fixed = (stats.total_fixed + (1 << k) - 1) >> k;
142
143 let params = FlexGateConfigParams { num_advice_per_phase, num_fixed, k };
144 #[cfg(feature = "display")]
145 {
146 for (phase, num_advice) in stats.total_advice_per_phase.iter().enumerate() {
147 println!("Gate Chip | Phase {phase}: {num_advice} advice cells",);
148 }
149 println!("Total {} fixed cells", stats.total_fixed);
150 log::info!("Auto-calculated config params:\n {params:#?}");
151 }
152 params
153 }
154}
155
156pub struct GateStatistics {
158 pub total_advice_per_phase: Vec<usize>,
160 pub total_fixed: usize,
162}