openvm_stark_backend/prover/
matrix.rs1use std::borrow::Borrow;
2
3use getset::CopyGetters;
4use p3_field::Field;
5use p3_matrix::dense::{DenseMatrix, RowMajorMatrix};
6use p3_maybe_rayon::prelude::*;
7use serde::{Deserialize, Serialize};
8
9use crate::prover::MatrixDimensions;
10
11impl<T, V: Borrow<[T]>> MatrixDimensions for DenseMatrix<T, V> {
12 fn height(&self) -> usize {
13 self.values.borrow().len() / self.width
14 }
15 fn width(&self) -> usize {
16 self.width
17 }
18}
19
20pub trait MatrixView<F>: MatrixDimensions {
26 fn get(&self, row_idx: usize, col_idx: usize) -> Option<&F> {
27 if col_idx >= self.width() || row_idx >= self.height() {
28 None
29 } else {
30 Some(unsafe { self.get_unchecked(row_idx, col_idx) })
32 }
33 }
34 unsafe fn get_unchecked(&self, row_idx: usize, col_idx: usize) -> &F;
40}
41
42#[derive(Clone, Debug, Serialize, Deserialize)]
43pub struct ColMajorMatrix<F> {
44 pub values: Vec<F>,
45 width: usize,
46 height: usize,
47}
48
49#[derive(Clone, Copy, Debug)]
50pub struct ColMajorMatrixView<'a, F> {
51 pub values: &'a [F],
52 width: usize,
53 height: usize,
54}
55
56#[derive(Clone, Copy, Debug, CopyGetters)]
58pub struct StridedColMajorMatrixView<'a, F> {
59 #[getset(get_copy = "pub")]
60 values: &'a [F],
61 width: usize,
62 height: usize,
63 #[getset(get_copy = "pub")]
65 stride: usize,
66}
67
68impl<F> ColMajorMatrix<F> {
69 pub fn new(values: Vec<F>, width: usize) -> Self {
70 assert_eq!(values.len() % width, 0);
71 let height = values.len() / width;
72 assert!(height.is_power_of_two());
73 Self {
74 values,
75 width,
76 height,
77 }
78 }
79
80 pub fn column(&self, col_idx: usize) -> &[F] {
81 let start = col_idx * self.height;
82 let end = start + self.height;
83 &self.values[start..end]
84 }
85
86 pub fn columns(&self) -> impl Iterator<Item = &[F]> {
87 self.values.chunks_exact(self.height)
88 }
89
90 pub fn as_view(&self) -> ColMajorMatrixView<'_, F> {
91 ColMajorMatrixView {
92 values: &self.values,
93 width: self.width,
94 height: self.height,
95 }
96 }
97
98 pub fn from_row_major(mat: &RowMajorMatrix<F>) -> Self
99 where
100 F: Field,
101 {
102 let mut values = F::zero_vec(mat.values.len());
103 let width = mat.width;
104 let height = mat.values.len() / mat.width;
105 values.par_iter_mut().enumerate().for_each(|(idx, value)| {
106 let r = idx % height;
107 let c = idx / height;
108 *value = unsafe { *mat.values.get_unchecked(r * width + c) };
110 });
111 Self {
112 values,
113 width,
114 height,
115 }
116 }
117}
118
119impl<F: Sync> ColMajorMatrix<F> {
120 pub fn par_columns(&self) -> impl ParallelIterator<Item = &[F]> {
121 self.values.par_chunks_exact(self.height)
122 }
123}
124
125impl<F> MatrixDimensions for ColMajorMatrix<F> {
126 fn width(&self) -> usize {
127 self.width
128 }
129 fn height(&self) -> usize {
130 self.height
131 }
132}
133
134impl<F> MatrixView<F> for ColMajorMatrix<F> {
135 unsafe fn get_unchecked(&self, row_idx: usize, col_idx: usize) -> &F {
136 debug_assert!(col_idx < self.width);
137 debug_assert!(row_idx < self.height);
138 self.values.get_unchecked(col_idx * self.height + row_idx)
139 }
140}
141
142impl<'a, F> ColMajorMatrixView<'a, F> {
143 pub fn new(values: &'a [F], width: usize) -> Self {
144 assert_eq!(values.len() % width, 0);
145 let height = values.len() / width;
146 debug_assert!(height == 0 || height.is_power_of_two());
147 Self {
148 values,
149 width,
150 height,
151 }
152 }
153
154 pub fn column(&self, col_idx: usize) -> &[F] {
155 let start = col_idx * self.height;
156 let end = start + self.height;
157 &self.values[start..end]
158 }
159
160 pub fn columns(&self) -> impl Iterator<Item = &[F]> {
161 self.values.chunks_exact(self.height)
162 }
163}
164
165impl<F> MatrixDimensions for ColMajorMatrixView<'_, F> {
166 fn width(&self) -> usize {
167 self.width
168 }
169 fn height(&self) -> usize {
170 self.height
171 }
172}
173
174impl<F> MatrixView<F> for ColMajorMatrixView<'_, F> {
175 unsafe fn get_unchecked(&self, row_idx: usize, col_idx: usize) -> &F {
176 debug_assert!(col_idx < self.width);
177 debug_assert!(row_idx < self.height);
178 self.values
179 .get_unchecked(col_maj_idx(row_idx, col_idx, self.height))
180 }
181}
182
183impl<'a, F> StridedColMajorMatrixView<'a, F> {
184 pub fn new(values: &'a [F], width: usize, stride: usize) -> Self {
185 assert_eq!(values.len() % (width * stride), 0);
186 let height = values.len() / (width * stride);
187 debug_assert!(height == 0 || height.is_power_of_two());
188 Self {
189 values,
190 width,
191 height,
192 stride,
193 }
194 }
195
196 pub fn to_matrix(&self) -> ColMajorMatrix<F>
197 where
198 F: Field,
199 {
200 let values: Vec<_> = (0..self.width * self.height)
201 .into_par_iter()
202 .map(|i| {
203 let r = i % self.height;
204 let c = i / self.height;
205 unsafe { *self.get_unchecked(r, c) }
206 })
207 .collect();
208 ColMajorMatrix::new(values, self.width)
209 }
210
211 pub fn to_row_major_matrix(&self) -> RowMajorMatrix<F>
212 where
213 F: Field,
214 {
215 let values: Vec<_> = (0..self.width * self.height)
216 .into_par_iter()
217 .map(|i| {
218 let r = i / self.width;
219 let c = i % self.width;
220 unsafe { *self.get_unchecked(r, c) }
221 })
222 .collect();
223 RowMajorMatrix::new(values, self.width)
224 }
225}
226
227impl<F> MatrixDimensions for StridedColMajorMatrixView<'_, F> {
228 fn width(&self) -> usize {
229 self.width
230 }
231 fn height(&self) -> usize {
232 self.height
233 }
234}
235
236impl<F> MatrixView<F> for StridedColMajorMatrixView<'_, F> {
237 unsafe fn get_unchecked(&self, row_idx: usize, col_idx: usize) -> &F {
238 debug_assert!(col_idx < self.width);
239 debug_assert!(row_idx < self.height);
240 self.values.get_unchecked(col_maj_idx(
241 row_idx * self.stride,
242 col_idx,
243 self.height * self.stride,
244 ))
245 }
246}
247
248impl<'a, F> From<ColMajorMatrixView<'a, F>> for StridedColMajorMatrixView<'a, F> {
249 fn from(mat: ColMajorMatrixView<'a, F>) -> Self {
250 Self::new(mat.values, mat.width, 1)
251 }
252}
253
254#[inline(always)]
255pub(crate) fn col_maj_idx(row_idx: usize, col_idx: usize, height: usize) -> usize {
256 col_idx * height + row_idx
257}