mirror of https://github.com/zcash/halo2.git
Move SingleChipLayouter into a submodule
It is a single-pass layouter, but we won't rename it for now.
This commit is contained in:
parent
d8e4f24df4
commit
b00a0df392
|
@ -1,13 +1,17 @@
|
|||
//! Implementations of common circuit layouters.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::{Cell, Layouter, Region, RegionIndex, RegionStart};
|
||||
use crate::arithmetic::FieldExt;
|
||||
use crate::plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation, Selector};
|
||||
use super::{Cell, RegionIndex};
|
||||
use crate::{
|
||||
arithmetic::FieldExt,
|
||||
plonk::{Advice, Any, Column, Error, Fixed, Permutation, Selector},
|
||||
};
|
||||
|
||||
mod single_pass;
|
||||
pub use single_pass::SingleChipLayouter;
|
||||
|
||||
/// Helper trait for implementing a custom [`Layouter`].
|
||||
///
|
||||
|
@ -37,6 +41,8 @@ use crate::plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation, S
|
|||
/// TODO: It would be great if we could constrain the columns in these types to be
|
||||
/// "logical" columns that are guaranteed to correspond to the chip (and have come from
|
||||
/// `Chip::Config`).
|
||||
///
|
||||
/// [`Layouter`]: super::Layouter
|
||||
pub trait RegionLayouter<F: FieldExt>: fmt::Debug {
|
||||
/// Enables a selector at the given offset.
|
||||
fn enable_selector<'v>(
|
||||
|
@ -75,97 +81,6 @@ pub trait RegionLayouter<F: FieldExt>: fmt::Debug {
|
|||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// A [`Layouter`] for a single-chip circuit.
|
||||
pub struct SingleChipLayouter<'a, F: FieldExt, CS: Assignment<F> + 'a> {
|
||||
cs: &'a mut CS,
|
||||
/// Stores the starting row for each region.
|
||||
regions: Vec<RegionStart>,
|
||||
/// Stores the first empty row for each column.
|
||||
columns: HashMap<Column<Any>, usize>,
|
||||
_marker: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F> + 'a> fmt::Debug for SingleChipLayouter<'a, F, CS> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SingleChipLayouter")
|
||||
.field("regions", &self.regions)
|
||||
.field("columns", &self.columns)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F>> SingleChipLayouter<'a, F, CS> {
|
||||
/// Creates a new single-chip layouter.
|
||||
pub fn new(cs: &'a mut CS) -> Result<Self, Error> {
|
||||
let ret = SingleChipLayouter {
|
||||
cs,
|
||||
regions: vec![],
|
||||
columns: HashMap::default(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F> + 'a> Layouter<F> for SingleChipLayouter<'a, F, CS> {
|
||||
type Root = Self;
|
||||
|
||||
fn assign_region<A, AR, N, NR>(&mut self, name: N, mut assignment: A) -> Result<AR, Error>
|
||||
where
|
||||
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
|
||||
N: Fn() -> NR,
|
||||
NR: Into<String>,
|
||||
{
|
||||
let region_index = self.regions.len();
|
||||
|
||||
// Get shape of the region.
|
||||
let mut shape = RegionShape::new(region_index.into());
|
||||
{
|
||||
let region: &mut dyn RegionLayouter<F> = &mut shape;
|
||||
assignment(region.into())?;
|
||||
}
|
||||
|
||||
// Lay out this region. We implement the simplest approach here: position the
|
||||
// region starting at the earliest row for which none of the columns are in use.
|
||||
let mut region_start = 0;
|
||||
for column in &shape.columns {
|
||||
region_start = cmp::max(region_start, self.columns.get(column).cloned().unwrap_or(0));
|
||||
}
|
||||
self.regions.push(region_start.into());
|
||||
|
||||
// Update column usage information.
|
||||
for column in shape.columns {
|
||||
self.columns.insert(column, region_start + shape.row_count);
|
||||
}
|
||||
|
||||
self.cs.enter_region(name);
|
||||
let mut region = SingleChipLayouterRegion::new(self, region_index.into());
|
||||
let result = {
|
||||
let region: &mut dyn RegionLayouter<F> = &mut region;
|
||||
assignment(region.into())
|
||||
}?;
|
||||
self.cs.exit_region();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
self.cs.push_namespace(name_fn)
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self, gadget_name: Option<String>) {
|
||||
self.cs.pop_namespace(gadget_name)
|
||||
}
|
||||
}
|
||||
|
||||
/// The shape of a region. For a region at a certain index, we track
|
||||
/// the set of columns it uses as well as the number of rows it uses.
|
||||
#[derive(Debug)]
|
||||
|
@ -259,104 +174,3 @@ impl<F: FieldExt> RegionLayouter<F> for RegionShape {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleChipLayouterRegion<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> {
|
||||
layouter: &'r mut SingleChipLayouter<'a, F, CS>,
|
||||
region_index: RegionIndex,
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> fmt::Debug
|
||||
for SingleChipLayouterRegion<'r, 'a, F, CS>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SingleChipLayouterRegion")
|
||||
.field("layouter", &self.layouter)
|
||||
.field("region_index", &self.region_index)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> SingleChipLayouterRegion<'r, 'a, F, CS> {
|
||||
fn new(layouter: &'r mut SingleChipLayouter<'a, F, CS>, region_index: RegionIndex) -> Self {
|
||||
SingleChipLayouterRegion {
|
||||
layouter,
|
||||
region_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> RegionLayouter<F>
|
||||
for SingleChipLayouterRegion<'r, 'a, F, CS>
|
||||
{
|
||||
fn enable_selector<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
selector: &Selector,
|
||||
offset: usize,
|
||||
) -> Result<(), Error> {
|
||||
self.layouter.cs.enable_selector(
|
||||
annotation,
|
||||
selector,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
)
|
||||
}
|
||||
|
||||
fn assign_advice<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
column: Column<Advice>,
|
||||
offset: usize,
|
||||
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
|
||||
) -> Result<Cell, Error> {
|
||||
self.layouter.cs.assign_advice(
|
||||
annotation,
|
||||
column,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
to,
|
||||
)?;
|
||||
|
||||
Ok(Cell {
|
||||
region_index: self.region_index,
|
||||
row_offset: offset,
|
||||
column: column.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn assign_fixed<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
column: Column<Fixed>,
|
||||
offset: usize,
|
||||
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
|
||||
) -> Result<Cell, Error> {
|
||||
self.layouter.cs.assign_fixed(
|
||||
annotation,
|
||||
column,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
to,
|
||||
)?;
|
||||
|
||||
Ok(Cell {
|
||||
region_index: self.region_index,
|
||||
row_offset: offset,
|
||||
column: column.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn constrain_equal(
|
||||
&mut self,
|
||||
permutation: &Permutation,
|
||||
left: Cell,
|
||||
right: Cell,
|
||||
) -> Result<(), Error> {
|
||||
self.layouter.cs.copy(
|
||||
permutation,
|
||||
left.column,
|
||||
*self.layouter.regions[*left.region_index] + left.row_offset,
|
||||
right.column,
|
||||
*self.layouter.regions[*right.region_index] + right.row_offset,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::{RegionLayouter, RegionShape};
|
||||
use crate::{
|
||||
arithmetic::FieldExt,
|
||||
circuit::{Cell, Layouter, Region, RegionIndex, RegionStart},
|
||||
plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation, Selector},
|
||||
};
|
||||
|
||||
/// A [`Layouter`] for a single-chip circuit.
|
||||
pub struct SingleChipLayouter<'a, F: FieldExt, CS: Assignment<F> + 'a> {
|
||||
cs: &'a mut CS,
|
||||
/// Stores the starting row for each region.
|
||||
regions: Vec<RegionStart>,
|
||||
/// Stores the first empty row for each column.
|
||||
columns: HashMap<Column<Any>, usize>,
|
||||
_marker: PhantomData<F>,
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F> + 'a> fmt::Debug for SingleChipLayouter<'a, F, CS> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SingleChipLayouter")
|
||||
.field("regions", &self.regions)
|
||||
.field("columns", &self.columns)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F>> SingleChipLayouter<'a, F, CS> {
|
||||
/// Creates a new single-chip layouter.
|
||||
pub fn new(cs: &'a mut CS) -> Result<Self, Error> {
|
||||
let ret = SingleChipLayouter {
|
||||
cs,
|
||||
regions: vec![],
|
||||
columns: HashMap::default(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, F: FieldExt, CS: Assignment<F> + 'a> Layouter<F> for SingleChipLayouter<'a, F, CS> {
|
||||
type Root = Self;
|
||||
|
||||
fn assign_region<A, AR, N, NR>(&mut self, name: N, mut assignment: A) -> Result<AR, Error>
|
||||
where
|
||||
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
|
||||
N: Fn() -> NR,
|
||||
NR: Into<String>,
|
||||
{
|
||||
let region_index = self.regions.len();
|
||||
|
||||
// Get shape of the region.
|
||||
let mut shape = RegionShape::new(region_index.into());
|
||||
{
|
||||
let region: &mut dyn RegionLayouter<F> = &mut shape;
|
||||
assignment(region.into())?;
|
||||
}
|
||||
|
||||
// Lay out this region. We implement the simplest approach here: position the
|
||||
// region starting at the earliest row for which none of the columns are in use.
|
||||
let mut region_start = 0;
|
||||
for column in &shape.columns {
|
||||
region_start = cmp::max(region_start, self.columns.get(column).cloned().unwrap_or(0));
|
||||
}
|
||||
self.regions.push(region_start.into());
|
||||
|
||||
// Update column usage information.
|
||||
for column in shape.columns {
|
||||
self.columns.insert(column, region_start + shape.row_count);
|
||||
}
|
||||
|
||||
self.cs.enter_region(name);
|
||||
let mut region = SingleChipLayouterRegion::new(self, region_index.into());
|
||||
let result = {
|
||||
let region: &mut dyn RegionLayouter<F> = &mut region;
|
||||
assignment(region.into())
|
||||
}?;
|
||||
self.cs.exit_region();
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn get_root(&mut self) -> &mut Self::Root {
|
||||
self
|
||||
}
|
||||
|
||||
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
||||
where
|
||||
NR: Into<String>,
|
||||
N: FnOnce() -> NR,
|
||||
{
|
||||
self.cs.push_namespace(name_fn)
|
||||
}
|
||||
|
||||
fn pop_namespace(&mut self, gadget_name: Option<String>) {
|
||||
self.cs.pop_namespace(gadget_name)
|
||||
}
|
||||
}
|
||||
|
||||
struct SingleChipLayouterRegion<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> {
|
||||
layouter: &'r mut SingleChipLayouter<'a, F, CS>,
|
||||
region_index: RegionIndex,
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> fmt::Debug
|
||||
for SingleChipLayouterRegion<'r, 'a, F, CS>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SingleChipLayouterRegion")
|
||||
.field("layouter", &self.layouter)
|
||||
.field("region_index", &self.region_index)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> SingleChipLayouterRegion<'r, 'a, F, CS> {
|
||||
fn new(layouter: &'r mut SingleChipLayouter<'a, F, CS>, region_index: RegionIndex) -> Self {
|
||||
SingleChipLayouterRegion {
|
||||
layouter,
|
||||
region_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> RegionLayouter<F>
|
||||
for SingleChipLayouterRegion<'r, 'a, F, CS>
|
||||
{
|
||||
fn enable_selector<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
selector: &Selector,
|
||||
offset: usize,
|
||||
) -> Result<(), Error> {
|
||||
self.layouter.cs.enable_selector(
|
||||
annotation,
|
||||
selector,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
)
|
||||
}
|
||||
|
||||
fn assign_advice<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
column: Column<Advice>,
|
||||
offset: usize,
|
||||
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
|
||||
) -> Result<Cell, Error> {
|
||||
self.layouter.cs.assign_advice(
|
||||
annotation,
|
||||
column,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
to,
|
||||
)?;
|
||||
|
||||
Ok(Cell {
|
||||
region_index: self.region_index,
|
||||
row_offset: offset,
|
||||
column: column.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn assign_fixed<'v>(
|
||||
&'v mut self,
|
||||
annotation: &'v (dyn Fn() -> String + 'v),
|
||||
column: Column<Fixed>,
|
||||
offset: usize,
|
||||
to: &'v mut (dyn FnMut() -> Result<F, Error> + 'v),
|
||||
) -> Result<Cell, Error> {
|
||||
self.layouter.cs.assign_fixed(
|
||||
annotation,
|
||||
column,
|
||||
*self.layouter.regions[*self.region_index] + offset,
|
||||
to,
|
||||
)?;
|
||||
|
||||
Ok(Cell {
|
||||
region_index: self.region_index,
|
||||
row_offset: offset,
|
||||
column: column.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn constrain_equal(
|
||||
&mut self,
|
||||
permutation: &Permutation,
|
||||
left: Cell,
|
||||
right: Cell,
|
||||
) -> Result<(), Error> {
|
||||
self.layouter.cs.copy(
|
||||
permutation,
|
||||
left.column,
|
||||
*self.layouter.regions[*left.region_index] + left.row_offset,
|
||||
right.column,
|
||||
*self.layouter.regions[*right.region_index] + right.row_offset,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue