Skip to main content

stwo_gpu/core/pcs/
utils.rs

1use core::ops::{Deref, DerefMut};
2
3use itertools::zip_eq;
4use serde::{Deserialize, Serialize};
5use std_shims::{vec, BTreeSet, Vec};
6
7use super::TreeSubspan;
8use crate::core::ColumnVec;
9
10/// A container that holds an element for each commitment tree.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TreeVec<T>(pub Vec<T>);
13
14impl<T> TreeVec<T> {
15    pub const fn new(vec: Vec<T>) -> TreeVec<T> {
16        TreeVec(vec)
17    }
18    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> TreeVec<U> {
19        TreeVec(self.0.into_iter().map(f).collect())
20    }
21    pub fn zip<U>(self, other: impl Into<TreeVec<U>>) -> TreeVec<(T, U)> {
22        let other = other.into();
23        TreeVec(self.0.into_iter().zip(other.0).collect())
24    }
25    pub fn zip_eq<U>(self, other: impl Into<TreeVec<U>>) -> TreeVec<(T, U)> {
26        let other = other.into();
27        TreeVec(zip_eq(self.0, other.0).collect())
28    }
29    pub fn as_ref(&self) -> TreeVec<&T> {
30        TreeVec(self.iter().collect())
31    }
32    pub fn as_mut(&mut self) -> TreeVec<&mut T> {
33        TreeVec(self.iter_mut().collect())
34    }
35}
36
37/// Converts `&TreeVec<T>` to `TreeVec<&T>`.
38impl<'a, T> From<&'a TreeVec<T>> for TreeVec<&'a T> {
39    fn from(val: &'a TreeVec<T>) -> Self {
40        val.as_ref()
41    }
42}
43
44/// Converts `&TreeVec<&Vec<T>>` to `TreeVec<Vec<&T>>`.
45impl<'a, T> From<&'a TreeVec<&'a Vec<T>>> for TreeVec<Vec<&'a T>> {
46    fn from(val: &'a TreeVec<&'a Vec<T>>) -> Self {
47        TreeVec(val.iter().map(|vec| vec.iter().collect()).collect())
48    }
49}
50
51impl<T> Deref for TreeVec<T> {
52    type Target = Vec<T>;
53    fn deref(&self) -> &Self::Target {
54        &self.0
55    }
56}
57
58impl<T> DerefMut for TreeVec<T> {
59    fn deref_mut(&mut self) -> &mut Self::Target {
60        &mut self.0
61    }
62}
63
64impl<T> Default for TreeVec<T> {
65    fn default() -> Self {
66        TreeVec(Vec::new())
67    }
68}
69
70impl<T> TreeVec<ColumnVec<T>> {
71    pub fn map_cols<U, F: FnMut(T) -> U>(self, mut f: F) -> TreeVec<ColumnVec<U>> {
72        TreeVec(
73            self.0
74                .into_iter()
75                .map(|column| column.into_iter().map(&mut f).collect())
76                .collect(),
77        )
78    }
79
80    #[cfg(feature = "parallel")]
81    pub fn par_map_cols<U, F>(self, f: F) -> TreeVec<ColumnVec<U>>
82    where
83        T: Send,
84        U: Send,
85        F: Fn(T) -> U + Sync + Send,
86    {
87        use rayon::iter::{IntoParallelIterator, ParallelIterator};
88        TreeVec(
89            self.0
90                .into_par_iter()
91                .map(|column| column.into_par_iter().map(&f).collect::<Vec<_>>())
92                .collect(),
93        )
94    }
95
96    /// Zips two [`TreeVec<ColumnVec<T>>`] with the same structure (number of columns in each tree).
97    /// The resulting [`TreeVec<ColumnVec<T>>`] has the same structure, with each value being a
98    /// tuple of the corresponding values from the input [`TreeVec<ColumnVec<T>>`].
99    pub fn zip_cols<U>(
100        self,
101        other: impl Into<TreeVec<ColumnVec<U>>>,
102    ) -> TreeVec<ColumnVec<(T, U)>> {
103        let other = other.into();
104        TreeVec(
105            zip_eq(self.0, other.0)
106                .map(|(column1, column2)| zip_eq(column1, column2).collect())
107                .collect(),
108        )
109    }
110
111    pub fn as_cols_ref(&self) -> TreeVec<ColumnVec<&T>> {
112        TreeVec(self.iter().map(|column| column.iter().collect()).collect())
113    }
114
115    /// Flattens the [`TreeVec<ColumnVec<T>>`] into a single [`ColumnVec`] with all the columns
116    /// combined.
117    pub fn flatten(self) -> ColumnVec<T> {
118        self.0.into_iter().flatten().collect()
119    }
120
121    /// Appends the columns of another [`TreeVec<ColumnVec<T>>`] to this one.
122    pub fn append_cols(&mut self, mut other: TreeVec<ColumnVec<T>>) {
123        let n_trees = self.0.len().max(other.0.len());
124        self.0.resize_with(n_trees, Default::default);
125        for (self_col, other_col) in self.0.iter_mut().zip(other.0.iter_mut()) {
126            self_col.append(other_col);
127        }
128    }
129
130    /// Concatenates the columns of multiple [`TreeVec<ColumnVec<T>>`] into a single
131    /// [`TreeVec<ColumnVec<T>>`].
132    pub fn concat_cols(
133        trees: impl Iterator<Item = TreeVec<ColumnVec<T>>>,
134    ) -> TreeVec<ColumnVec<T>> {
135        let mut result = TreeVec::default();
136        for tree in trees {
137            result.append_cols(tree);
138        }
139        result
140    }
141
142    /// Extracts a sub-tree based on the specified locations.
143    ///
144    /// # Panics
145    ///
146    /// If two or more locations have the same tree index.
147    pub fn sub_tree(&self, locations: &[TreeSubspan]) -> TreeVec<ColumnVec<&T>> {
148        let tree_indices: BTreeSet<usize> = locations.iter().map(|l| l.tree_index).collect();
149        assert_eq!(tree_indices.len(), locations.len());
150        let max_tree_index = tree_indices.iter().max().unwrap_or(&0);
151        let mut res = TreeVec(vec![Vec::new(); max_tree_index + 1]);
152
153        for &location in locations {
154            // TODO(andrew): Throwing error here might be better instead.
155            let chunk = self.get_chunk(location).unwrap();
156            res[location.tree_index] = chunk;
157        }
158
159        res
160    }
161
162    fn get_chunk(&self, location: TreeSubspan) -> Option<ColumnVec<&T>> {
163        let tree = self.0.get(location.tree_index)?;
164        let chunk = tree.get(location.col_start..location.col_end)?;
165        Some(chunk.iter().collect())
166    }
167}
168
169impl<T> TreeVec<&ColumnVec<T>> {
170    pub fn map_cols<U, F: FnMut(&T) -> U>(self, mut f: F) -> TreeVec<ColumnVec<U>> {
171        TreeVec(
172            self.0
173                .into_iter()
174                .map(|column| column.iter().map(&mut f).collect())
175                .collect(),
176        )
177    }
178}
179
180impl<'a, T> From<&'a TreeVec<ColumnVec<T>>> for TreeVec<ColumnVec<&'a T>> {
181    fn from(val: &'a TreeVec<ColumnVec<T>>) -> Self {
182        val.as_cols_ref()
183    }
184}
185
186impl<T> TreeVec<ColumnVec<Vec<T>>> {
187    /// Flattens a [`TreeVec<ColumnVec<T>>`] of [Vec]s into a single [Vec] with all the elements
188    /// combined.
189    pub fn flatten_cols(self) -> Vec<T> {
190        self.0.into_iter().flatten().flatten().collect()
191    }
192}
193
194pub fn prepare_preprocessed_query_positions(
195    query_positions: &[usize],
196    max_log_size: u32,
197    pp_max_log_size: u32,
198) -> Vec<usize> {
199    if pp_max_log_size == 0 {
200        return vec![];
201    };
202    if max_log_size < pp_max_log_size {
203        return query_positions
204            .iter()
205            .map(|pos| (pos >> 1 << (pp_max_log_size - max_log_size + 1)) + (pos & 1))
206            .collect();
207    }
208    query_positions
209        .iter()
210        .map(|pos| (pos >> (max_log_size - pp_max_log_size + 1) << 1) + (pos & 1))
211        .collect()
212}