forked from lambdaclass/lambdaworks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.rs
170 lines (144 loc) · 5.65 KB
/
table.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use crate::frame::Frame;
use lambdaworks_math::field::{
element::FieldElement,
traits::{IsField, IsSubFieldOf},
};
/// A two-dimensional Table holding field elements, arranged in a row-major order.
/// This is the basic underlying data structure used for any two-dimensional component in the
/// the STARK protocol implementation, such as the `TraceTable` and the `EvaluationFrame`.
/// Since this struct is a representation of a two-dimensional table, all rows should have the same
/// length.
#[derive(Clone, Default, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Table<F: IsField> {
pub data: Vec<FieldElement<F>>,
pub width: usize,
pub height: usize,
}
impl<'t, F: IsField> Table<F> {
/// Crates a new Table instance from a one-dimensional array in row major order
/// and the intended width of the table.
pub fn new(data: Vec<FieldElement<F>>, width: usize) -> Self {
// Check if the intented width is 0, used for creating an empty table.
if width == 0 {
return Self {
data: Vec::new(),
width,
height: 0,
};
}
// Check that the one-dimensional data makes sense to be interpreted as a 2D one.
debug_assert!(crate::debug::validate_2d_structure(&data, width));
let height = data.len() / width;
Self {
data,
width,
height,
}
}
/// Creates a Table instance from a vector of the intended columns.
pub fn from_columns(columns: Vec<Vec<FieldElement<F>>>) -> Self {
if columns.is_empty() {
return Self::new(Vec::new(), 0);
}
let height = columns[0].len();
// Check that all columns have the same length for integrity
debug_assert!(columns.iter().all(|c| c.len() == height));
let width = columns.len();
let mut data = Vec::with_capacity(width * height);
for row_idx in 0..height {
for column in columns.iter() {
data.push(column[row_idx].clone());
}
}
Self::new(data, width)
}
/// Returns a vector of vectors of field elements representing the table rows
pub fn rows(&self) -> Vec<Vec<FieldElement<F>>> {
self.data.chunks(self.width).map(|r| r.to_vec()).collect()
}
/// Given a row index, returns a reference to that row as a slice of field elements.
pub fn get_row(&self, row_idx: usize) -> &[FieldElement<F>] {
let row_offset = row_idx * self.width;
&self.data[row_offset..row_offset + self.width]
}
/// Given a slice of field elements representing a row, appends it to
/// the end of the table.
pub fn append_row(&mut self, row: &[FieldElement<F>]) {
debug_assert_eq!(row.len(), self.width);
self.data.extend_from_slice(row);
self.height += 1
}
/// Returns a reference to the last row of the table
pub fn last_row(&self) -> &[FieldElement<F>] {
self.get_row(self.height - 1)
}
/// Returns a vector of vectors of field elements representing the table
/// columns
pub fn columns(&self) -> Vec<Vec<FieldElement<F>>> {
(0..self.width)
.map(|col_idx| {
(0..self.height)
.map(|row_idx| self.data[row_idx * self.width + col_idx].clone())
.collect()
})
.collect()
}
pub fn get_column(&self, col_idx: usize) -> Vec<FieldElement<F>> {
(0..self.height)
.map(|row_idx| self.data[row_idx * self.width + col_idx].clone())
.collect()
}
/// Given row and column indexes, returns the stored field element in that position of the table.
pub fn get(&self, row: usize, col: usize) -> &FieldElement<F> {
let idx = row * self.width + col;
&self.data[idx]
}
pub fn set(&mut self, row: usize, col: usize, value: FieldElement<F>) {
let idx = row * self.width + col;
self.data[idx] = value;
}
/// Given a step size, converts the given table into a `Frame`.
pub fn into_frame(&'t self, main_trace_columns: usize, step_size: usize) -> Frame<'t, F, F> {
debug_assert!(self.height % step_size == 0);
let steps = (0..self.height)
.step_by(step_size)
.map(|initial_row_idx| {
let end_row_idx = initial_row_idx + step_size;
let mut step_main_data: Vec<&'t [FieldElement<F>]> = Vec::new();
let mut step_aux_data: Vec<&'t [FieldElement<F>]> = Vec::new();
(initial_row_idx..end_row_idx).for_each(|row_idx| {
let row = self.get_row(row_idx);
step_main_data.push(&row[..main_trace_columns]);
step_aux_data.push(&row[main_trace_columns..]);
});
TableView::new(step_main_data, step_aux_data)
})
.collect();
Frame::new(steps)
}
}
/// A view of a contiguos subset of rows of a table.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TableView<'t, F, E>
where
E: IsField,
F: IsSubFieldOf<F>,
{
pub data: Vec<&'t [FieldElement<F>]>,
pub aux_data: Vec<&'t [FieldElement<E>]>,
}
impl<'t, F, E> TableView<'t, F, E>
where
E: IsField,
F: IsSubFieldOf<F>,
{
pub fn new(data: Vec<&'t [FieldElement<F>]>, aux_data: Vec<&'t [FieldElement<E>]>) -> Self {
Self { data, aux_data }
}
pub fn get_main_evaluation_element(&self, row: usize, col: usize) -> &FieldElement<F> {
&self.data[row][col]
}
pub fn get_aux_evaluation_element(&self, row: usize, col: usize) -> &FieldElement<E> {
&self.aux_data[row][col]
}
}