openvm_stark_backend/prover/quotient/
single.rsuse std::cmp::min;
use itertools::Itertools;
use p3_commit::PolynomialSpace;
use p3_field::{AbstractExtensionField, AbstractField, PackedValue};
use p3_matrix::{dense::RowMajorMatrixView, stack::VerticalPair, Matrix};
use p3_maybe_rayon::prelude::*;
use p3_util::log2_strict_usize;
use tracing::instrument;
use crate::{
air_builders::{prover::ProverConstraintFolder, symbolic::SymbolicConstraints},
config::{Domain, PackedChallenge, PackedVal, StarkGenericConfig, Val},
interaction::RapPhaseSeqKind,
rap::{PartitionedBaseAir, Rap},
};
#[allow(clippy::too_many_arguments)]
#[instrument(
name = "compute single RAP quotient polynomial",
level = "trace",
skip_all
)]
pub fn compute_single_rap_quotient_values<'a, SC, R, Mat>(
rap: &'a R,
symbolic_constraints: &SymbolicConstraints<Val<SC>>,
trace_domain: Domain<SC>,
quotient_domain: Domain<SC>,
preprocessed_trace_on_quotient_domain: Mat,
partitioned_main_lde_on_quotient_domain: Vec<Mat>,
after_challenge_lde_on_quotient_domain: Vec<Mat>,
challenges: &[Vec<PackedChallenge<SC>>],
alpha: SC::Challenge,
public_values: &'a [Val<SC>],
exposed_values_after_challenge: &'a [&'a [PackedChallenge<SC>]],
rap_phase_seq_kind: RapPhaseSeqKind,
interaction_chunk_size: usize,
) -> Vec<SC::Challenge>
where
R: for<'b> Rap<ProverConstraintFolder<'b, SC>> + PartitionedBaseAir<Val<SC>> + Sync + ?Sized,
SC: StarkGenericConfig,
Mat: Matrix<Val<SC>> + Sync,
{
let quotient_size = quotient_domain.size();
let preprocessed_width = preprocessed_trace_on_quotient_domain.width();
let mut sels = trace_domain.selectors_on_coset(quotient_domain);
let qdb = log2_strict_usize(quotient_size) - log2_strict_usize(trace_domain.size());
let next_step = 1 << qdb;
let ext_degree = SC::Challenge::D;
let mut alpha_powers = alpha
.powers()
.take(symbolic_constraints.constraints.len())
.collect_vec();
alpha_powers.reverse();
for _ in quotient_size..PackedVal::<SC>::WIDTH {
sels.is_first_row.push(Val::<SC>::default());
sels.is_last_row.push(Val::<SC>::default());
sels.is_transition.push(Val::<SC>::default());
sels.inv_zeroifier.push(Val::<SC>::default());
}
(0..quotient_size)
.into_par_iter()
.step_by(PackedVal::<SC>::WIDTH)
.flat_map_iter(|i_start| {
let wrap = |i| i % quotient_size;
let i_range = i_start..i_start + PackedVal::<SC>::WIDTH;
let is_first_row = *PackedVal::<SC>::from_slice(&sels.is_first_row[i_range.clone()]);
let is_last_row = *PackedVal::<SC>::from_slice(&sels.is_last_row[i_range.clone()]);
let is_transition = *PackedVal::<SC>::from_slice(&sels.is_transition[i_range.clone()]);
let inv_zeroifier = *PackedVal::<SC>::from_slice(&sels.inv_zeroifier[i_range.clone()]);
let [preprocessed_local, preprocessed_next] = [0, 1].map(|step_idx| {
(0..preprocessed_width)
.map(|col| {
PackedVal::<SC>::from_fn(|offset| {
Matrix::get(
&preprocessed_trace_on_quotient_domain,
wrap(i_start + offset + step_idx * next_step),
col,
)
})
})
.collect_vec()
});
let partitioned_main_pairs = partitioned_main_lde_on_quotient_domain
.iter()
.map(|lde| {
let width = lde.width();
[0, 1].map(|step_idx| {
(0..width)
.map(|col| {
PackedVal::<SC>::from_fn(|offset| {
lde.get(wrap(i_start + offset + step_idx * next_step), col)
})
})
.collect_vec()
})
})
.collect_vec();
let after_challenge_pairs = after_challenge_lde_on_quotient_domain
.iter()
.map(|lde| {
let base_width = lde.width();
[0, 1].map(|step_idx| {
(0..base_width)
.step_by(ext_degree)
.map(|col| {
PackedChallenge::<SC>::from_base_fn(|i| {
PackedVal::<SC>::from_fn(|offset| {
lde.get(
wrap(i_start + offset + step_idx * next_step),
col + i,
)
})
})
})
.collect_vec()
})
})
.collect_vec();
let accumulator = PackedChallenge::<SC>::ZERO;
let mut folder = ProverConstraintFolder {
preprocessed: VerticalPair::new(
RowMajorMatrixView::new_row(&preprocessed_local),
RowMajorMatrixView::new_row(&preprocessed_next),
),
partitioned_main: partitioned_main_pairs
.iter()
.map(|[local, next]| {
VerticalPair::new(
RowMajorMatrixView::new_row(local),
RowMajorMatrixView::new_row(next),
)
})
.collect(),
after_challenge: after_challenge_pairs
.iter()
.map(|[local, next]| {
VerticalPair::new(
RowMajorMatrixView::new_row(local),
RowMajorMatrixView::new_row(next),
)
})
.collect(),
challenges,
is_first_row,
is_last_row,
is_transition,
alpha_powers: &alpha_powers,
accumulator,
public_values,
exposed_values_after_challenge,
interactions: vec![],
interaction_chunk_size,
rap_phase_seq_kind,
has_common_main: rap.common_main_width() > 0,
constraint_index: 0,
};
rap.eval(&mut folder);
let quotient = folder.accumulator * inv_zeroifier;
let width = min(PackedVal::<SC>::WIDTH, quotient_size);
(0..width).map(move |idx_in_packing| {
let quotient_value = (0..<SC::Challenge as AbstractExtensionField<Val<SC>>>::D)
.map(|coeff_idx| quotient.as_base_slice()[coeff_idx].as_slice()[idx_in_packing])
.collect::<Vec<_>>();
SC::Challenge::from_base_slice("ient_value)
})
})
.collect()
}