mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-06 07:43:10 +00:00
Merge pull request #79 from mir-protocol/lower_max_constraint_degree
Optimize max constraint degree when searching for gate trees
This commit is contained in:
commit
e44c4ff679
@ -231,12 +231,11 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_polys(&self, gates: &[PrefixedGate<F, D>]) -> Vec<PolynomialValues<F>> {
|
||||
let num_constants = gates
|
||||
.iter()
|
||||
.map(|gate| gate.gate.0.num_constants() + gate.prefix.len())
|
||||
.max()
|
||||
.unwrap();
|
||||
fn constant_polys(
|
||||
&self,
|
||||
gates: &[PrefixedGate<F, D>],
|
||||
num_constants: usize,
|
||||
) -> Vec<PolynomialValues<F>> {
|
||||
let constants_per_gate = self
|
||||
.gate_instances
|
||||
.iter()
|
||||
@ -295,14 +294,13 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
info!("degree after blinding & padding: {}", degree);
|
||||
|
||||
let gates = self.gates.iter().cloned().collect();
|
||||
let gate_tree = Tree::from_gates(gates);
|
||||
let (gate_tree, max_filtered_constraint_degree, num_constants) = Tree::from_gates(gates);
|
||||
let prefixed_gates = PrefixedGate::from_tree(gate_tree);
|
||||
|
||||
let degree_bits = log2_strict(degree);
|
||||
let subgroup = F::two_adic_subgroup(degree_bits);
|
||||
|
||||
let constant_vecs = self.constant_polys(&prefixed_gates);
|
||||
let num_constants = constant_vecs.len();
|
||||
let constant_vecs = self.constant_polys(&prefixed_gates, num_constants);
|
||||
|
||||
let k_is = get_unique_coset_shifts(degree, self.config.num_routed_wires);
|
||||
let sigma_vecs = self.sigma_vecs(&k_is, &subgroup);
|
||||
@ -350,7 +348,7 @@ impl<F: Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
config: self.config,
|
||||
degree_bits,
|
||||
gates: prefixed_gates,
|
||||
max_filtered_constraint_degree_bits: 3, // TODO: compute this correctly once filters land.
|
||||
max_filtered_constraint_degree,
|
||||
num_gate_constraints,
|
||||
num_constants,
|
||||
k_is,
|
||||
|
||||
@ -146,7 +146,7 @@ pub struct CommonCircuitData<F: Extendable<D>, const D: usize> {
|
||||
pub(crate) gates: Vec<PrefixedGate<F, D>>,
|
||||
|
||||
/// The maximum degree of a filter times a constraint by any gate.
|
||||
pub(crate) max_filtered_constraint_degree_bits: usize,
|
||||
pub(crate) max_filtered_constraint_degree: usize,
|
||||
|
||||
/// The largest number of constraints imposed by any gate.
|
||||
pub(crate) num_gate_constraints: usize,
|
||||
@ -184,7 +184,7 @@ impl<F: Extendable<D>, const D: usize> CommonCircuitData<F, D> {
|
||||
}
|
||||
|
||||
pub fn quotient_degree(&self) -> usize {
|
||||
((1 << self.max_filtered_constraint_degree_bits) - 1) * self.degree()
|
||||
(self.max_filtered_constraint_degree - 1) * self.degree()
|
||||
}
|
||||
|
||||
pub fn total_constraints(&self) -> usize {
|
||||
|
||||
@ -57,8 +57,9 @@ impl<F: Extendable<D>, const D: usize> Tree<GateRef<F, D>> {
|
||||
/// For this construction, we use the greedy algorithm in `Self::find_tree`.
|
||||
/// This latter function greedily adds gates at the depth where
|
||||
/// `filtered_deg(gate)=D, constant_wires(gate)=C` to ensure no space is wasted.
|
||||
/// We return the first tree found in this manner.
|
||||
pub fn from_gates(mut gates: Vec<GateRef<F, D>>) -> Self {
|
||||
/// We return the first tree found in this manner, along with it's maximum filtered degree
|
||||
/// and the number of constant wires needed when using this tree.
|
||||
pub fn from_gates(mut gates: Vec<GateRef<F, D>>) -> (Self, usize, usize) {
|
||||
let timer = std::time::Instant::now();
|
||||
gates.sort_unstable_by_key(|g| (-(g.0.degree() as isize), -(g.0.num_constants() as isize)));
|
||||
|
||||
@ -67,14 +68,30 @@ impl<F: Extendable<D>, const D: usize> Tree<GateRef<F, D>> {
|
||||
// So we can restrict our search space by setting `max_degree` to a power of 2.
|
||||
let max_degree = 1 << max_degree_bits;
|
||||
for max_constants in 1..100 {
|
||||
if let Some(mut tree) = Self::find_tree(&gates, max_degree, max_constants) {
|
||||
tree.shorten();
|
||||
if let Some(mut best_tree) = Self::find_tree(&gates, max_degree, max_constants) {
|
||||
let mut best_num_constants = best_tree.num_constants();
|
||||
let mut best_degree = max_degree;
|
||||
// Iterate backwards from `max_degree` to try to find a tree with a lower degree
|
||||
// but the same number of constants.
|
||||
'optdegree: for degree in (0..max_degree).rev() {
|
||||
if let Some(mut tree) = Self::find_tree(&gates, degree, max_constants) {
|
||||
let num_constants = tree.num_constants();
|
||||
if num_constants > best_num_constants {
|
||||
break 'optdegree;
|
||||
} else {
|
||||
best_degree = degree;
|
||||
best_num_constants = num_constants;
|
||||
best_tree = tree;
|
||||
}
|
||||
}
|
||||
}
|
||||
info!(
|
||||
"Found tree with max degree {} in {}s.",
|
||||
max_degree,
|
||||
"Found tree with max degree {} and {} constants wires in {}s.",
|
||||
best_degree,
|
||||
best_num_constants,
|
||||
timer.elapsed().as_secs_f32()
|
||||
);
|
||||
return tree;
|
||||
return (best_tree, best_degree, best_num_constants);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,6 +106,7 @@ impl<F: Extendable<D>, const D: usize> Tree<GateRef<F, D>> {
|
||||
for g in gates {
|
||||
tree.try_add_gate(g, max_degree, max_constants)?;
|
||||
}
|
||||
tree.shorten();
|
||||
Some(tree)
|
||||
}
|
||||
|
||||
@ -180,6 +198,24 @@ impl<F: Extendable<D>, const D: usize> Tree<GateRef<F, D>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the tree's maximum filtered constraint degree.
|
||||
fn max_filtered_degree(&self) -> usize {
|
||||
self.traversal()
|
||||
.into_iter()
|
||||
.map(|(g, p)| g.0.degree() + p.len())
|
||||
.max()
|
||||
.expect("Empty tree.")
|
||||
}
|
||||
|
||||
/// Returns the number of constant wires needed to fit all prefixes and gate constants.
|
||||
fn num_constants(&self) -> usize {
|
||||
self.traversal()
|
||||
.into_iter()
|
||||
.map(|(g, p)| g.0.num_constants() + p.len())
|
||||
.max()
|
||||
.expect("Empty tree.")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -212,7 +248,7 @@ mod tests {
|
||||
];
|
||||
let len = gates.len();
|
||||
|
||||
let tree = Tree::from_gates(gates.clone());
|
||||
let (tree, _, _) = Tree::from_gates(gates.clone());
|
||||
let mut gates_with_prefix = tree.traversal();
|
||||
for (g, p) in &gates_with_prefix {
|
||||
info!(
|
||||
|
||||
@ -327,7 +327,7 @@ mod tests {
|
||||
},
|
||||
degree_bits: 0,
|
||||
gates: vec![],
|
||||
max_filtered_constraint_degree_bits: 0,
|
||||
max_filtered_constraint_degree: 0,
|
||||
num_gate_constraints: 0,
|
||||
num_constants: 4,
|
||||
k_is: vec![F::ONE; 6],
|
||||
|
||||
@ -12,7 +12,7 @@ use crate::polynomial::commitment::ListPolynomialCommitment;
|
||||
use crate::polynomial::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use crate::proof::Proof;
|
||||
use crate::timed;
|
||||
use crate::util::transpose;
|
||||
use crate::util::{log2_ceil, transpose};
|
||||
use crate::vars::EvaluationVarsBase;
|
||||
use crate::witness::{PartialWitness, Witness};
|
||||
|
||||
@ -219,23 +219,22 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
||||
alphas: &[F],
|
||||
) -> Vec<PolynomialCoeffs<F>> {
|
||||
let num_challenges = common_data.config.num_challenges;
|
||||
let max_filtered_constraint_degree_bits = log2_ceil(common_data.max_filtered_constraint_degree);
|
||||
assert!(
|
||||
common_data.max_filtered_constraint_degree_bits <= common_data.config.rate_bits,
|
||||
max_filtered_constraint_degree_bits <= common_data.config.rate_bits,
|
||||
"Having constraints of degree higher than the rate is not supported yet. \
|
||||
If we need this in the future, we can precompute the larger LDE before computing the `ListPolynomialCommitment`s."
|
||||
);
|
||||
|
||||
// We reuse the LDE computed in `ListPolynomialCommitment` and extract every `step` points to get
|
||||
// an LDE matching `max_filtered_constraint_degree`.
|
||||
let step =
|
||||
1 << (common_data.config.rate_bits - common_data.max_filtered_constraint_degree_bits);
|
||||
let step = 1 << (common_data.config.rate_bits - max_filtered_constraint_degree_bits);
|
||||
// When opening the `Z`s polys at the "next" point in Plonk, need to look at the point `next_step`
|
||||
// steps away since we work on an LDE of degree `max_filtered_constraint_degree`.
|
||||
let next_step = 1 << common_data.max_filtered_constraint_degree_bits;
|
||||
let next_step = 1 << max_filtered_constraint_degree_bits;
|
||||
|
||||
let points = F::two_adic_subgroup(
|
||||
common_data.degree_bits + common_data.max_filtered_constraint_degree_bits,
|
||||
);
|
||||
let points =
|
||||
F::two_adic_subgroup(common_data.degree_bits + max_filtered_constraint_degree_bits);
|
||||
let lde_size = points.len();
|
||||
|
||||
// Retrieve the LDE values at index `i`.
|
||||
@ -243,10 +242,8 @@ fn compute_quotient_polys<'a, F: Extendable<D>, const D: usize>(
|
||||
comm.get_lde_values(i * step)
|
||||
};
|
||||
|
||||
let z_h_on_coset = ZeroPolyOnCoset::new(
|
||||
common_data.degree_bits,
|
||||
common_data.max_filtered_constraint_degree_bits,
|
||||
);
|
||||
let z_h_on_coset =
|
||||
ZeroPolyOnCoset::new(common_data.degree_bits, max_filtered_constraint_degree_bits);
|
||||
|
||||
let quotient_values: Vec<Vec<F>> = points
|
||||
.into_par_iter()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user