halo2_base/gates/circuit/
builder.rs1use std::sync::{Arc, Mutex};
2
3use getset::{Getters, MutGetters, Setters};
4use itertools::Itertools;
5
6use crate::{
7 gates::{
8 circuit::CircuitBuilderStage,
9 flex_gate::{
10 threads::{GateStatistics, MultiPhaseCoreManager, SinglePhaseCoreManager},
11 MultiPhaseThreadBreakPoints, MAX_PHASE,
12 },
13 range::RangeConfig,
14 RangeChip,
15 },
16 halo2_proofs::{
17 circuit::{Layouter, Region},
18 plonk::{Column, Instance},
19 },
20 utils::ScalarField,
21 virtual_region::{
22 copy_constraints::{CopyConstraintManager, SharedCopyConstraintManager},
23 lookups::LookupAnyManager,
24 manager::VirtualRegionManager,
25 },
26 AssignedValue, Context,
27};
28
29use super::BaseCircuitParams;
30
31pub type RangeCircuitBuilder<F> = BaseCircuitBuilder<F>;
33
34#[derive(Clone, Debug, Getters, MutGetters, Setters)]
46pub struct BaseCircuitBuilder<F: ScalarField> {
47 #[getset(get = "pub", get_mut = "pub", set = "pub")]
49 pub(super) core: MultiPhaseCoreManager<F>,
50 #[getset(get = "pub", get_mut = "pub", set = "pub")]
52 pub(super) lookup_manager: [LookupAnyManager<F, 1>; MAX_PHASE],
53 pub config_params: BaseCircuitParams,
55 pub assigned_instances: Vec<Vec<AssignedValue<F>>>,
57}
58
59impl<F: ScalarField> Default for BaseCircuitBuilder<F> {
60 fn default() -> Self {
63 Self::new(false)
64 }
65}
66
67impl<F: ScalarField> BaseCircuitBuilder<F> {
68 pub fn new(witness_gen_only: bool) -> Self {
82 let core = MultiPhaseCoreManager::new(witness_gen_only);
83 let lookup_manager = [(); MAX_PHASE]
84 .map(|_| LookupAnyManager::new(witness_gen_only, core.copy_manager.clone()));
85 Self { core, lookup_manager, config_params: Default::default(), assigned_instances: vec![] }
86 }
87
88 pub fn from_stage(stage: CircuitBuilderStage) -> Self {
90 Self::new(stage.witness_gen_only()).unknown(stage == CircuitBuilderStage::Keygen)
91 }
92
93 pub fn prover(
95 config_params: BaseCircuitParams,
96 break_points: MultiPhaseThreadBreakPoints,
97 ) -> Self {
98 Self::new(true).use_params(config_params).use_break_points(break_points)
99 }
100
101 pub fn set_copy_manager(&mut self, copy_manager: SharedCopyConstraintManager<F>) {
103 for lm in &mut self.lookup_manager {
104 lm.set_copy_manager(copy_manager.clone());
105 }
106 self.core.set_copy_manager(copy_manager);
107 }
108
109 pub fn use_copy_manager(mut self, copy_manager: SharedCopyConstraintManager<F>) -> Self {
111 self.set_copy_manager(copy_manager);
112 self
113 }
114
115 pub fn deep_clone(&self) -> Self {
117 let cm: CopyConstraintManager<F> = self.core.copy_manager.lock().unwrap().clone();
118 let cm_ref = Arc::new(Mutex::new(cm));
119 let mut clone = self.clone().use_copy_manager(cm_ref.clone());
120 for lm in &mut clone.lookup_manager {
121 *lm = lm.deep_clone(cm_ref.clone());
122 }
123 clone
124 }
125
126 pub fn lookup_bits(&self) -> Option<usize> {
128 self.config_params.lookup_bits
129 }
130
131 pub fn set_lookup_bits(&mut self, lookup_bits: usize) {
133 self.config_params.lookup_bits = Some(lookup_bits);
134 }
135
136 pub fn use_lookup_bits(mut self, lookup_bits: usize) -> Self {
138 self.set_lookup_bits(lookup_bits);
139 self
140 }
141
142 pub fn set_k(&mut self, k: usize) {
144 self.config_params.k = k;
145 }
146
147 pub fn use_k(mut self, k: usize) -> Self {
149 self.set_k(k);
150 self
151 }
152
153 pub fn set_instance_columns(&mut self, num_instance_columns: usize) {
155 self.config_params.num_instance_columns = num_instance_columns;
156 while self.assigned_instances.len() < num_instance_columns {
157 self.assigned_instances.push(vec![]);
158 }
159 assert_eq!(self.assigned_instances.len(), num_instance_columns);
160 }
161
162 pub fn use_instance_columns(mut self, num_instance_columns: usize) -> Self {
164 self.set_instance_columns(num_instance_columns);
165 self
166 }
167
168 pub fn set_params(&mut self, params: BaseCircuitParams) {
170 self.set_instance_columns(params.num_instance_columns);
171 self.config_params = params;
172 }
173
174 pub fn use_params(mut self, params: BaseCircuitParams) -> Self {
176 self.set_params(params);
177 self
178 }
179
180 pub fn break_points(&self) -> MultiPhaseThreadBreakPoints {
182 self.core
183 .phase_manager
184 .iter()
185 .map(|pm| pm.break_points.borrow().as_ref().expect("break points not set").clone())
186 .collect()
187 }
188
189 pub fn set_break_points(&mut self, break_points: MultiPhaseThreadBreakPoints) {
191 if break_points.is_empty() {
192 return;
193 }
194 self.core.touch(break_points.len() - 1);
195 for (pm, bp) in self.core.phase_manager.iter().zip_eq(break_points) {
196 *pm.break_points.borrow_mut() = Some(bp);
197 }
198 }
199
200 pub fn use_break_points(mut self, break_points: MultiPhaseThreadBreakPoints) -> Self {
202 self.set_break_points(break_points);
203 self
204 }
205
206 pub fn witness_gen_only(&self) -> bool {
208 self.core.witness_gen_only()
209 }
210
211 pub fn unknown(mut self, use_unknown: bool) -> Self {
214 self.core = self.core.unknown(use_unknown);
215 self
216 }
217
218 pub fn clear(&mut self) {
220 self.core.clear();
221 for lm in &mut self.lookup_manager {
222 lm.clear();
223 }
224 self.assigned_instances.iter_mut().for_each(|c| c.clear());
225 }
226
227 pub fn main(&mut self, phase: usize) -> &mut Context<F> {
230 self.core.main(phase)
231 }
232
233 pub fn pool(&mut self, phase: usize) -> &mut SinglePhaseCoreManager<F> {
235 self.core.phase_manager.get_mut(phase).unwrap()
236 }
237
238 pub fn new_thread(&mut self, phase: usize) -> &mut Context<F> {
241 self.core.new_thread(phase)
242 }
243
244 pub fn statistics(&self) -> RangeStatistics {
246 let gate = self.core.statistics();
247 let total_lookup_advice_per_phase = self.total_lookup_advice_per_phase();
248 RangeStatistics { gate, total_lookup_advice_per_phase }
249 }
250
251 fn total_lookup_advice_per_phase(&self) -> Vec<usize> {
252 self.lookup_manager.iter().map(|lm| lm.total_rows()).collect()
253 }
254
255 pub fn calculate_params(&mut self, minimum_rows: Option<usize>) -> BaseCircuitParams {
261 let k = self.config_params.k;
262 let ni = self.config_params.num_instance_columns;
263 assert_ne!(k, 0, "k must be set");
264 let max_rows = (1 << k) - minimum_rows.unwrap_or(0);
265 let gate_params = self.core.calculate_params(k, minimum_rows);
266 let total_lookup_advice_per_phase = self.total_lookup_advice_per_phase();
267 let num_lookup_advice_per_phase = total_lookup_advice_per_phase
268 .iter()
269 .map(|count| count.div_ceil(max_rows))
270 .collect::<Vec<_>>();
271
272 let params = BaseCircuitParams {
273 k: gate_params.k,
274 num_advice_per_phase: gate_params.num_advice_per_phase,
275 num_fixed: gate_params.num_fixed,
276 num_lookup_advice_per_phase,
277 lookup_bits: self.lookup_bits(),
278 num_instance_columns: ni,
279 };
280 self.config_params = params.clone();
281 #[cfg(feature = "display")]
282 {
283 println!("Total range check advice cells to lookup per phase: {total_lookup_advice_per_phase:?}");
284 log::info!("Auto-calculated config params:\n {params:#?}");
285 }
286 params
287 }
288
289 pub fn assign_instances(
292 &self,
293 instance_columns: &[Column<Instance>],
294 mut layouter: impl Layouter<F>,
295 ) {
296 if !self.core.witness_gen_only() {
297 for (instances, instance_col) in self.assigned_instances.iter().zip_eq(instance_columns)
299 {
300 for (i, instance) in instances.iter().enumerate() {
301 let cell = instance.cell.unwrap();
302 let copy_manager = self.core.copy_manager.lock().unwrap();
303 let cell =
304 copy_manager.assigned_advices.get(&cell).expect("instance not assigned");
305 layouter.constrain_instance(*cell, *instance_col, i);
306 }
307 }
308 }
309 }
310
311 pub fn range_chip(&self) -> RangeChip<F> {
313 RangeChip::new(
314 self.config_params.lookup_bits.expect("lookup bits not set"),
315 self.lookup_manager.clone(),
316 )
317 }
318
319 pub fn assign_lookups_in_phase(
328 &self,
329 config: &RangeConfig<F>,
330 region: &mut Region<F>,
331 phase: usize,
332 ) {
333 let lookup_manager = self.lookup_manager.get(phase).expect("too many phases");
334 if lookup_manager.total_rows() == 0 {
335 return;
336 }
337 if let Some(q_lookup) = config.q_lookup.get(phase).and_then(|q| *q) {
338 assert_eq!(config.gate.basic_gates[phase].len(), 1);
340 if !self.witness_gen_only() {
341 let cells_to_lookup = lookup_manager.cells_to_lookup.lock().unwrap();
342 for advice in cells_to_lookup.iter().flat_map(|(_, advices)| advices) {
343 let cell = advice[0].cell.as_ref().unwrap();
344 let copy_manager = self.core.copy_manager.lock().unwrap();
345 let acell = copy_manager.assigned_advices[cell];
346 assert_eq!(
347 acell.column,
348 config.gate.basic_gates[phase][0].value.into(),
349 "lookup column does not match"
350 );
351 q_lookup.enable(region, acell.row_offset).unwrap();
352 }
353 }
354 } else {
355 let lookup_cols = config
356 .lookup_advice
357 .get(phase)
358 .expect("No special lookup advice columns")
359 .iter()
360 .map(|c| [*c])
361 .collect_vec();
362 lookup_manager.assign_raw(&lookup_cols, region);
363 }
364 let _ = lookup_manager.assigned.set(());
365 }
366}
367
368pub struct RangeStatistics {
370 pub gate: GateStatistics,
372 pub total_lookup_advice_per_phase: Vec<usize>,
374}
375
376impl<F: ScalarField> AsRef<BaseCircuitBuilder<F>> for BaseCircuitBuilder<F> {
377 fn as_ref(&self) -> &BaseCircuitBuilder<F> {
378 self
379 }
380}
381
382impl<F: ScalarField> AsMut<BaseCircuitBuilder<F>> for BaseCircuitBuilder<F> {
383 fn as_mut(&mut self) -> &mut BaseCircuitBuilder<F> {
384 self
385 }
386}