remainder/
circuit_layout.rs

1//! Defines the utilities for taking a list of nodes and turning it into a
2//! layedout circuit
3use std::collections::{hash_map::Entry, HashMap};
4use std::fmt::Debug;
5use std::hash::Hash;
6
7use serde::{Deserialize, Serialize};
8use shared_types::Field;
9
10use crate::{
11    layer::LayerId,
12    mle::{dense::DenseMle, evals::MultilinearExtension, mle_description::MleDescription},
13};
14
15use anyhow::{anyhow, Result};
16
17/// A HashMap that records during circuit compilation where nodes live in the
18/// circuit and what data they yield.
19#[derive(Debug)]
20pub struct CircuitEvalMap<F: Field>(pub(crate) HashMap<CircuitLocation, MultilinearExtension<F>>);
21/// A map that maps layer ID to all the MLEs that are output from that layer.
22/// Together these MLEs are combined along with the information from their
23/// prefix bits to form the layerwise bookkeeping table.
24pub type LayerMap<F> = HashMap<LayerId, Vec<DenseMle<F>>>;
25
26impl<F: Field> CircuitEvalMap<F> {
27    /// Create a new circuit map, which maps circuit location to the data stored
28    /// at that location.removing
29    pub fn new() -> Self {
30        Self(HashMap::new())
31    }
32
33    /// Using the circuit location, which is a layer_id and prefix_bits tuple,
34    /// get the data that exists here.
35    pub fn get_data_from_circuit_mle(
36        &self,
37        circuit_mle: &MleDescription<F>,
38    ) -> Result<&MultilinearExtension<F>> {
39        let circuit_location =
40            CircuitLocation::new(circuit_mle.layer_id(), circuit_mle.prefix_bits());
41        let result = self
42            .0
43            .get(&circuit_location)
44            .ok_or(anyhow!("Circuit location not found!"));
45        if let Ok(actual_result) = result {
46            assert_eq!(actual_result.num_vars(), circuit_mle.num_free_vars());
47        }
48        result
49    }
50
51    /// Adds a new node to the CircuitMap
52    pub fn add_node(&mut self, circuit_location: CircuitLocation, value: MultilinearExtension<F>) {
53        self.0.insert(circuit_location, value);
54    }
55
56    /// Destructively convert this into a map that maps LayerId to the
57    /// [MultilinearExtension]s that generate claims on this area. This is to
58    /// aid in claim aggregation, so we know the parts of the layerwise
59    /// bookkeeping table in order to aggregate claims on this layer.
60    pub fn convert_to_layer_map(mut self) -> LayerMap<F> {
61        let mut layer_map = HashMap::<LayerId, Vec<DenseMle<F>>>::new();
62        self.0.drain().for_each(|(circuit_location, data)| {
63            let corresponding_mle = DenseMle::new_with_prefix_bits(
64                data,
65                circuit_location.layer_id,
66                circuit_location.prefix_bits,
67            );
68            if let Entry::Vacant(e) = layer_map.entry(circuit_location.layer_id) {
69                e.insert(vec![corresponding_mle]);
70            } else {
71                layer_map
72                    .get_mut(&circuit_location.layer_id)
73                    .unwrap()
74                    .push(corresponding_mle);
75            }
76        });
77        layer_map
78    }
79}
80
81impl<F: Field> Default for CircuitEvalMap<F> {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87/// The location of a Node in the circuit
88#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
89pub struct CircuitLocation {
90    /// The LayerId this node has been placed into
91    pub layer_id: LayerId,
92    /// Any prefix_bits neccessary to differenciate claims made onto this node
93    /// from other nodes in the same layer
94    pub prefix_bits: Vec<bool>,
95}
96
97impl CircuitLocation {
98    /// Creates a new CircuitLocation
99    pub fn new(layer_id: LayerId, prefix_bits: Vec<bool>) -> Self {
100        Self {
101            layer_id,
102            prefix_bits,
103        }
104    }
105}