mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-07 16:23:12 +00:00
Keep track of the last used RAM gate
This commit is contained in:
parent
a35cd98b03
commit
3f0b5ab9d3
@ -374,12 +374,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
let x_index_within_coset = self.le_sum(x_index_within_coset_bits.iter());
|
let x_index_within_coset = self.le_sum(x_index_within_coset_bits.iter());
|
||||||
|
|
||||||
// Check consistency with our old evaluation from the previous round.
|
// Check consistency with our old evaluation from the previous round.
|
||||||
self.random_access_padded(
|
self.random_access_extension(x_index_within_coset, old_eval, evals.clone());
|
||||||
x_index_within_coset,
|
|
||||||
old_eval,
|
|
||||||
evals.clone(),
|
|
||||||
1 << config.cap_height,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Infer P(y) from {P(x)}_{x^arity=y}.
|
// Infer P(y) from {P(x)}_{x^arity=y}.
|
||||||
old_eval = with_context!(
|
old_eval = with_context!(
|
||||||
|
|||||||
@ -6,27 +6,60 @@ use crate::iop::target::Target;
|
|||||||
use crate::plonk::circuit_builder::CircuitBuilder;
|
use crate::plonk::circuit_builder::CircuitBuilder;
|
||||||
|
|
||||||
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||||
|
/// Finds the last available random access gate with the given `vec_size` or add one if there aren't any.
|
||||||
|
/// Returns `(g,i)` such that there is a random access gate with the given `vec_size` at index
|
||||||
|
/// `g` and the gate's `i`-th random access is available.
|
||||||
|
fn find_random_acces_gate(&mut self, vec_size: usize) -> (usize, usize) {
|
||||||
|
let (gate, i) = self
|
||||||
|
.free_random_access
|
||||||
|
.get(&vec_size)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let gate = self.add_gate(
|
||||||
|
RandomAccessGate::new_from_config(&self.config, vec_size),
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
(gate, 0)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update `free_random_access` with new values.
|
||||||
|
if i < RandomAccessGate::<F, D>::max_num_copies(
|
||||||
|
self.config.num_routed_wires,
|
||||||
|
self.config.num_wires,
|
||||||
|
vec_size,
|
||||||
|
) - 1
|
||||||
|
{
|
||||||
|
self.free_random_access.insert(vec_size, (gate, i + 1));
|
||||||
|
} else {
|
||||||
|
self.free_random_access.remove(&vec_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
(gate, i)
|
||||||
|
}
|
||||||
/// Checks that an `ExtensionTarget` matches a vector at a non-deterministic index.
|
/// Checks that an `ExtensionTarget` matches a vector at a non-deterministic index.
|
||||||
/// Note: `access_index` is not range-checked.
|
/// Note: `access_index` is not range-checked.
|
||||||
pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec<Target>) {
|
pub fn random_access(&mut self, access_index: Target, claimed_element: Target, v: Vec<Target>) {
|
||||||
debug_assert!(!v.is_empty());
|
let vec_size = v.len();
|
||||||
if v.len() == 1 {
|
debug_assert!(vec_size > 0);
|
||||||
|
if vec_size == 1 {
|
||||||
return self.connect(claimed_element, v[0]);
|
return self.connect(claimed_element, v[0]);
|
||||||
}
|
}
|
||||||
let gate = RandomAccessGate::new(1, v.len());
|
let (gate_index, copy) = self.find_random_acces_gate(vec_size);
|
||||||
let gate_index = self.add_gate(gate.clone(), vec![]);
|
let dummy_gate = RandomAccessGate::<F, D>::new_from_config(&self.config, vec_size);
|
||||||
|
|
||||||
let copy = 0;
|
|
||||||
v.iter().enumerate().for_each(|(i, &val)| {
|
v.iter().enumerate().for_each(|(i, &val)| {
|
||||||
self.connect(val, Target::wire(gate_index, gate.wire_list_item(i, copy)));
|
self.connect(
|
||||||
|
val,
|
||||||
|
Target::wire(gate_index, dummy_gate.wire_list_item(i, copy)),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
self.connect(
|
self.connect(
|
||||||
access_index,
|
access_index,
|
||||||
Target::wire(gate_index, gate.wire_access_index(copy)),
|
Target::wire(gate_index, dummy_gate.wire_access_index(copy)),
|
||||||
);
|
);
|
||||||
self.connect(
|
self.connect(
|
||||||
claimed_element,
|
claimed_element,
|
||||||
Target::wire(gate_index, gate.wire_claimed_element(copy)),
|
Target::wire(gate_index, dummy_gate.wire_claimed_element(copy)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,50 +71,14 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
claimed_element: ExtensionTarget<D>,
|
claimed_element: ExtensionTarget<D>,
|
||||||
v: Vec<ExtensionTarget<D>>,
|
v: Vec<ExtensionTarget<D>>,
|
||||||
) {
|
) {
|
||||||
debug_assert!(!v.is_empty());
|
for i in 0..D {
|
||||||
if v.len() == 1 {
|
self.random_access(
|
||||||
return self.connect_extension(claimed_element, v[0]);
|
|
||||||
}
|
|
||||||
let gate = RandomAccessGate::new(D, v.len());
|
|
||||||
let gate_index = self.add_gate(gate.clone(), vec![]);
|
|
||||||
|
|
||||||
for copy in 0..D {
|
|
||||||
v.iter().enumerate().for_each(|(i, &val)| {
|
|
||||||
self.connect(
|
|
||||||
val.0[copy],
|
|
||||||
Target::wire(gate_index, gate.wire_list_item(i, copy)),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
self.connect(
|
|
||||||
access_index,
|
access_index,
|
||||||
Target::wire(gate_index, gate.wire_access_index(copy)),
|
claimed_element.0[i],
|
||||||
);
|
v.iter().map(|et| et.0[i]).collect(),
|
||||||
self.connect(
|
|
||||||
claimed_element.0[copy],
|
|
||||||
Target::wire(gate_index, gate.wire_claimed_element(copy)),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `random_access`, but first pads `v` to a given minimum length. This can help to avoid
|
|
||||||
/// having multiple `RandomAccessGate`s with different sizes.
|
|
||||||
pub fn random_access_padded(
|
|
||||||
&mut self,
|
|
||||||
access_index: Target,
|
|
||||||
claimed_element: ExtensionTarget<D>,
|
|
||||||
mut v: Vec<ExtensionTarget<D>>,
|
|
||||||
min_length: usize,
|
|
||||||
) {
|
|
||||||
debug_assert!(!v.is_empty());
|
|
||||||
if v.len() == 1 {
|
|
||||||
return self.connect_extension(claimed_element, v[0]);
|
|
||||||
}
|
|
||||||
let zero = self.zero_extension();
|
|
||||||
if v.len() < min_length {
|
|
||||||
v.resize(8, zero);
|
|
||||||
}
|
|
||||||
self.random_access_extension(access_index, claimed_element, v);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -31,12 +31,16 @@ impl<F: RichField + Extendable<D>, const D: usize> RandomAccessGate<F, D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_from_config(config: &CircuitConfig, vec_size: usize) -> Self {
|
pub fn new_from_config(config: &CircuitConfig, vec_size: usize) -> Self {
|
||||||
let num_copies = Self::max_num_copies(config.num_routed_wires, vec_size);
|
let num_copies = Self::max_num_copies(config.num_routed_wires, config.num_wires, vec_size);
|
||||||
Self::new(num_copies, vec_size)
|
Self::new(num_copies, vec_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_num_copies(num_routed_wires: usize, vec_size: usize) -> usize {
|
pub fn max_num_copies(num_routed_wires: usize, num_wires: usize, vec_size: usize) -> usize {
|
||||||
num_routed_wires / (2 + vec_size)
|
// Need `(2 + vec_size) * num_copies` routed wires
|
||||||
|
(num_routed_wires / (2 + vec_size)).min(
|
||||||
|
// Need `(2 + 4*vec_size) * num_copies` wires
|
||||||
|
num_wires / (2 + 4 * vec_size),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wire_access_index(&self, copy: usize) -> usize {
|
pub fn wire_access_index(&self, copy: usize) -> usize {
|
||||||
@ -79,7 +83,7 @@ impl<F: RichField + Extendable<D>, const D: usize> RandomAccessGate<F, D> {
|
|||||||
debug_assert!(copy < self.num_copies);
|
debug_assert!(copy < self.num_copies);
|
||||||
self.start_of_intermediate_wires()
|
self.start_of_intermediate_wires()
|
||||||
+ self.vec_size * self.num_copies
|
+ self.vec_size * self.num_copies
|
||||||
+ copy * self.vec_size
|
+ self.vec_size * copy
|
||||||
+ i
|
+ i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,6 +73,10 @@ pub struct CircuitBuilder<F: RichField + Extendable<D>, const D: usize> {
|
|||||||
/// these constants with gate index `g` and already using `i` arithmetic operations.
|
/// these constants with gate index `g` and already using `i` arithmetic operations.
|
||||||
pub(crate) free_arithmetic: HashMap<(F, F), (usize, usize)>,
|
pub(crate) free_arithmetic: HashMap<(F, F), (usize, usize)>,
|
||||||
|
|
||||||
|
/// A map `(c0, c1) -> (g, i)` from constants `vec_size` to an available arithmetic gate using
|
||||||
|
/// these constants with gate index `g` and already using `i` random accesses.
|
||||||
|
pub(crate) free_random_access: HashMap<usize, (usize, usize)>,
|
||||||
|
|
||||||
// `current_switch_gates[chunk_size - 1]` contains None if we have no switch gates with the value
|
// `current_switch_gates[chunk_size - 1]` contains None if we have no switch gates with the value
|
||||||
// chunk_size, and contains `(g, i, c)`, if the gate `g`, at index `i`, already contains `c` copies
|
// chunk_size, and contains `(g, i, c)`, if the gate `g`, at index `i`, already contains `c` copies
|
||||||
// of switches
|
// of switches
|
||||||
@ -94,6 +98,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
|||||||
constants_to_targets: HashMap::new(),
|
constants_to_targets: HashMap::new(),
|
||||||
targets_to_constants: HashMap::new(),
|
targets_to_constants: HashMap::new(),
|
||||||
free_arithmetic: HashMap::new(),
|
free_arithmetic: HashMap::new(),
|
||||||
|
free_random_access: HashMap::new(),
|
||||||
current_switch_gates: Vec::new(),
|
current_switch_gates: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user