1use crate::column::{Column, ColumnCount, ColumnRef};
9use crate::error::Error;
10use field_cat::Field;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct RowCount(usize);
24
25impl RowCount {
26 #[must_use]
28 pub fn new(n: usize) -> Self {
29 Self(n)
30 }
31
32 #[must_use]
34 pub fn count(self) -> usize {
35 self.0
36 }
37}
38
39impl core::fmt::Display for RowCount {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 write!(f, "{}", self.0)
42 }
43}
44
45#[derive(Debug, Clone)]
71pub struct Trace<F: Field> {
72 data: Vec<F>,
73 column_count: ColumnCount,
74 row_count: RowCount,
75}
76
77impl<F: Field> Trace<F> {
78 pub fn from_rows(column_count: ColumnCount, rows: &[Vec<F>]) -> Result<Self, Error> {
87 if rows.is_empty() {
88 Err(Error::EmptyTrace)
89 } else {
90 let data: Result<Vec<F>, Error> = rows.iter().enumerate().try_fold(
92 Vec::with_capacity(rows.len() * column_count.count()),
93 |acc, (i, row)| {
94 if row.len() == column_count.count() {
95 Ok(acc.into_iter().chain(row.iter().cloned()).collect())
96 } else {
97 Err(Error::RowLengthMismatch {
98 row: i,
99 expected: column_count.count(),
100 actual: row.len(),
101 })
102 }
103 },
104 );
105 Ok(Self {
106 data: data?,
107 column_count,
108 row_count: RowCount::new(rows.len()),
109 })
110 }
111 }
112
113 #[must_use]
115 pub fn column_count(&self) -> ColumnCount {
116 self.column_count
117 }
118
119 #[must_use]
121 pub fn row_count(&self) -> RowCount {
122 self.row_count
123 }
124
125 pub fn get(&self, row: usize, col: Column) -> Result<F, Error> {
132 if row >= self.row_count.count() || col.index() >= self.column_count.count() {
133 Err(Error::ColumnOutOfBounds {
134 index: col.index(),
135 column_count: self.column_count.count(),
136 })
137 } else {
138 Ok(self.data[row * self.column_count.count() + col.index()].clone())
139 }
140 }
141
142 pub fn row_pair_assignment(
151 &self,
152 row: usize,
153 ) -> Result<impl Fn(ColumnRef) -> Result<F, Error> + '_, Error> {
154 if row + 1 >= self.row_count.count() {
155 Err(Error::InsufficientRows {
156 row_count: self.row_count.count(),
157 })
158 } else {
159 Ok(move |cr: ColumnRef| {
160 let (r, c) = match cr {
161 ColumnRef::Current(col) => (row, col),
162 ColumnRef::Next(col) => (row + 1, col),
163 };
164 self.get(r, c)
165 })
166 }
167 }
168
169 pub fn column_values(&self, col: Column) -> Result<Vec<F>, Error> {
177 if col.index() >= self.column_count.count() {
178 Err(Error::ColumnOutOfBounds {
179 index: col.index(),
180 column_count: self.column_count.count(),
181 })
182 } else {
183 Ok((0..self.row_count.count())
184 .map(|r| self.data[r * self.column_count.count() + col.index()].clone())
185 .collect())
186 }
187 }
188
189 #[must_use]
191 pub fn data(&self) -> &[F] {
192 &self.data
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199 use field_cat::F101;
200
201 fn fib_trace() -> Result<Trace<F101>, Error> {
202 Trace::from_rows(
203 ColumnCount::new(2),
204 &[
205 vec![F101::new(1), F101::new(1)],
206 vec![F101::new(1), F101::new(2)],
207 vec![F101::new(2), F101::new(3)],
208 vec![F101::new(3), F101::new(5)],
209 ],
210 )
211 }
212
213 #[test]
214 fn from_rows_and_get() -> Result<(), Error> {
215 let t = fib_trace()?;
216 assert_eq!(t.row_count(), RowCount::new(4));
217 assert_eq!(t.column_count(), ColumnCount::new(2));
218 assert_eq!(t.get(0, Column::new(0))?, F101::new(1));
219 assert_eq!(t.get(3, Column::new(1))?, F101::new(5));
220 Ok(())
221 }
222
223 #[test]
224 fn empty_rows_fails() {
225 let result = Trace::<F101>::from_rows(ColumnCount::new(2), &[]);
226 assert!(result.is_err());
227 }
228
229 #[test]
230 fn wrong_row_length_fails() {
231 let result = Trace::from_rows(
232 ColumnCount::new(2),
233 &[vec![F101::new(1), F101::new(2)], vec![F101::new(3)]],
234 );
235 assert!(result.is_err());
236 }
237
238 #[test]
239 fn column_values_extraction() -> Result<(), Error> {
240 let t = fib_trace()?;
241 let col0 = t.column_values(Column::new(0))?;
242 assert_eq!(
243 col0,
244 vec![F101::new(1), F101::new(1), F101::new(2), F101::new(3)]
245 );
246 Ok(())
247 }
248
249 #[test]
250 fn row_pair_assignment_works() -> Result<(), Error> {
251 let t = fib_trace()?;
252 let assign = t.row_pair_assignment(1)?;
253 assert_eq!(assign(ColumnRef::Current(Column::new(0)))?, F101::new(1));
255 assert_eq!(assign(ColumnRef::Current(Column::new(1)))?, F101::new(2));
256 assert_eq!(assign(ColumnRef::Next(Column::new(0)))?, F101::new(2));
257 assert_eq!(assign(ColumnRef::Next(Column::new(1)))?, F101::new(3));
258 Ok(())
259 }
260
261 #[test]
262 fn row_pair_at_last_row_fails() -> Result<(), Error> {
263 let t = fib_trace()?;
264 let result = t.row_pair_assignment(3);
266 assert!(result.is_err());
267 Ok(())
268 }
269}