miden_core/advice/
map.rs

1use alloc::{
2    collections::{
3        BTreeMap,
4        btree_map::{Entry, IntoIter},
5    },
6    sync::Arc,
7    vec::Vec,
8};
9
10use crate::{
11    Felt, Word,
12    utils::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
13};
14
15// ADVICE MAP
16// ================================================================================================
17
18/// Defines a set of non-deterministic (advice) inputs which the VM can access by their keys.
19///
20/// Each key maps to one or more field element. To access the elements, the VM can move the values
21/// associated with a given key onto the advice stack using `adv.push_mapval` instruction. The VM
22/// can also insert new values into the advice map during execution.
23#[derive(Debug, Clone, Default, PartialEq, Eq)]
24pub struct AdviceMap(BTreeMap<Word, Arc<[Felt]>>);
25
26/// Pair representing a key-value entry in an [`AdviceMap`]
27type MapEntry = (Word, Arc<[Felt]>);
28
29impl AdviceMap {
30    /// Returns the values associated with given key.
31    pub fn get(&self, key: &Word) -> Option<&Arc<[Felt]>> {
32        self.0.get(key)
33    }
34
35    /// Returns true if the key has a corresponding value in the map.
36    pub fn contains_key(&self, key: &Word) -> bool {
37        self.0.contains_key(key)
38    }
39
40    /// Inserts a value, returning the previous value if the key was already set.
41    pub fn insert(&mut self, key: Word, value: impl Into<Arc<[Felt]>>) -> Option<Arc<[Felt]>> {
42        self.0.insert(key, value.into())
43    }
44
45    /// Removes the value associated with the key and returns the removed element.
46    pub fn remove(&mut self, key: &Word) -> Option<Arc<[Felt]>> {
47        self.0.remove(key)
48    }
49
50    /// Return an iteration over all entries in the map.
51    pub fn iter(&self) -> impl Iterator<Item = (&Word, &Arc<[Felt]>)> {
52        self.0.iter()
53    }
54
55    /// Returns the number of key value pairs in the advice map.
56    pub fn len(&self) -> usize {
57        self.0.len()
58    }
59
60    /// Returns true if the advice map is empty.
61    pub fn is_empty(&self) -> bool {
62        self.0.is_empty()
63    }
64
65    /// Gets the given key's corresponding entry in the map for in-place manipulation.
66    pub fn entry(&mut self, key: Word) -> Entry<'_, Word, Arc<[Felt]>> {
67        self.0.entry(key)
68    }
69
70    /// Merges all entries from the given [`AdviceMap`] into the current advice map.
71    ///
72    /// If an entry from the new map already exists with the same key but different value,
73    /// an error is returned containing the existing entry along with the value that would replace
74    /// it. The current map remains unchanged.
75    pub fn merge(&mut self, other: &Self) -> Result<(), (MapEntry, Arc<[Felt]>)> {
76        if let Some(conflict) = self.find_conflicting_entry(other) {
77            Err(conflict)
78        } else {
79            self.merge_new(other);
80            Ok(())
81        }
82    }
83
84    /// Merges entries from `other`, but only for keys not already present in `self`.
85    fn merge_new(&mut self, other: &Self) {
86        for (key, value) in other.iter() {
87            self.0.entry(*key).or_insert_with(|| value.clone());
88        }
89    }
90
91    /// Finds the first key that exists in both `self` and `other` with different values.
92    ///
93    /// # Returns
94    /// - `Some` containing the conflicting key, its value from `self`, and the value from `other`.
95    /// - `None` if there are no conflicting values.
96    fn find_conflicting_entry(&self, other: &Self) -> Option<(MapEntry, Arc<[Felt]>)> {
97        for (key, new_value) in other.iter() {
98            if let Some(existing_value) = self.get(key)
99                && existing_value != new_value
100            {
101                // Found a conflict.
102                return Some(((*key, existing_value.clone()), new_value.clone()));
103            }
104        }
105        // No conflicts found.
106        None
107    }
108}
109
110impl From<BTreeMap<Word, Arc<[Felt]>>> for AdviceMap {
111    fn from(value: BTreeMap<Word, Arc<[Felt]>>) -> Self {
112        Self(value)
113    }
114}
115
116impl From<BTreeMap<Word, Vec<Felt>>> for AdviceMap {
117    fn from(value: BTreeMap<Word, Vec<Felt>>) -> Self {
118        value.into_iter().collect()
119    }
120}
121
122impl IntoIterator for AdviceMap {
123    type Item = (Word, Arc<[Felt]>);
124    type IntoIter = IntoIter<Word, Arc<[Felt]>>;
125
126    fn into_iter(self) -> Self::IntoIter {
127        self.0.into_iter()
128    }
129}
130
131impl<V> FromIterator<(Word, V)> for AdviceMap
132where
133    V: Into<Arc<[Felt]>>,
134{
135    fn from_iter<I>(iter: I) -> Self
136    where
137        I: IntoIterator<Item = (Word, V)>,
138    {
139        iter.into_iter()
140            .map(|(key, value)| (key, value.into()))
141            .collect::<BTreeMap<Word, Arc<[Felt]>>>()
142            .into()
143    }
144}
145
146impl<V> Extend<(Word, V)> for AdviceMap
147where
148    V: Into<Arc<[Felt]>>,
149{
150    fn extend<I>(&mut self, iter: I)
151    where
152        I: IntoIterator<Item = (Word, V)>,
153    {
154        self.0.extend(iter.into_iter().map(|(key, value)| (key, value.into())))
155    }
156}
157
158impl Serializable for AdviceMap {
159    fn write_into<W: ByteWriter>(&self, target: &mut W) {
160        target.write_usize(self.0.len());
161        for (key, values) in self.0.iter() {
162            target.write((key, values.to_vec()));
163        }
164    }
165}
166
167impl Deserializable for AdviceMap {
168    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
169        let mut map = BTreeMap::new();
170        let count = source.read_usize()?;
171        for _ in 0..count {
172            let (key, values): (Word, Vec<Felt>) = source.read()?;
173            map.insert(key, Arc::from(values));
174        }
175        Ok(Self(map))
176    }
177}
178
179#[cfg(test)]
180mod tests {
181    use super::*;
182
183    #[test]
184    fn test_advice_map_serialization() {
185        let mut map1 = AdviceMap::default();
186        map1.insert(Word::default(), vec![Felt::from(1u32), Felt::from(2u32)]);
187
188        let bytes = map1.to_bytes();
189
190        let map2 = AdviceMap::read_from_bytes(&bytes).unwrap();
191
192        assert_eq!(map1, map2);
193    }
194}