From Spreadsheet to Trace Polynomials

In the previous section, we created a table (aka spreadsheet). In this section, we will convert the table into something called trace polynomials.

As we can see in Figure 2, the cells in each column of the table can be seen as evaluations of a Lagrange polynomial. A characteristic of a Lagrange polynomial is that interpolating \(n\) distinct points will result in a unique polynomial of at most \(n-1\) degrees. So if we consider each row value \(f(x_i)\) as the evaluation of a distinct point \(x_i\), we can get a unique polynomial of degree \(num\_rows-1\) for each column, which is also known as a trace polynomial.
We will explain why using a polynomial representation is useful in the next section, but for now, let's see how we can create trace polynomials for our code. Note that we are building upon the code from the previous section, so there's not much new code here.
fn main() {
// --snip--
// Convert table to trace polynomials
let domain = CanonicCoset::new(log_num_rows).circle_domain();
let _trace: ColumnVec<CircleEvaluation<SimdBackend, M31, BitReversedOrder>> =
vec![col_1, col_2]
.into_iter()
.map(|col| CircleEvaluation::new(domain, col))
.collect();
}
Here, domain
refers to the \(x_i\) values used to interpolate the trace polynomials. For example, \(x_1, x_2\) values in Figure 2 are the domain values for our example (in reality, we need the size of the domain needs to be 16 as we have 16 rows). We can ignore terms like CanonicCoset
and .circle_domain()
for now, but should note that the log_num_rows
in CanonicCoset::new(log_num_rows).circle_domain()
needs to be equal to the log of the actual number of rows that are used in the table.
Now that we have created 2 trace polynomials for our 2 columns, let's move on to the next section where we commit to those polynomials!