stwo_gpu_constraint_framework/
lib.rs1#![cfg_attr(feature = "prover", feature(portable_simd))]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4mod component;
6
7#[cfg(feature = "prover")]
8pub mod expr;
9mod info;
10pub mod logup;
11mod point;
12pub mod preprocessed_columns;
13#[cfg(all(feature = "prover", feature = "std"))]
14mod prover;
15
16use core::array;
17use core::fmt::Debug;
18use core::ops::{Add, AddAssign, Mul, Neg, Sub};
19
20pub use component::{FrameworkComponent, FrameworkEval, TraceLocationAllocator};
21pub use info::InfoEvaluator;
22use num_traits::{One, Zero};
23pub use point::PointEvaluator;
24use preprocessed_columns::PreProcessedColumnId;
25#[cfg(all(feature = "prover", feature = "std"))]
26pub use prover::{
27 assert_constraints_on_polys, assert_constraints_on_trace, relation_tracker, AssertEvaluator,
28 CpuDomainEvaluator, FractionWriter, LogupColGenerator, LogupTraceGenerator,
29 SimdDomainEvaluator,
30};
31
32#[cfg(all(feature = "prover", feature = "std", feature = "gpu"))]
34pub use prover::{
35 is_gpu_constraint_kernels_enabled, set_gpu_constraint_kernels_enabled, will_use_gpu_kernels,
36 GpuDomainEvaluator,
37};
38use std_shims::Vec;
39use stwo::core::fields::m31::BaseField;
40use stwo::core::fields::qm31::{SecureField, SECURE_EXTENSION_DEGREE};
41use stwo::core::fields::FieldExpOps;
42use stwo::core::Fraction;
43
44#[rustfmt::skip]
45pub use stwo::core::verifier::PREPROCESSED_TRACE_IDX;
46pub const ORIGINAL_TRACE_IDX: usize = 1;
47pub const INTERACTION_TRACE_IDX: usize = 2;
48
49type Batching = Vec<usize>;
55
56pub trait EvalAtRow {
58 type F: FieldExpOps
63 + Clone
64 + Debug
65 + Zero
66 + Neg<Output = Self::F>
67 + AddAssign
68 + AddAssign<BaseField>
69 + Add<Self::F, Output = Self::F>
70 + Sub<Self::F, Output = Self::F>
71 + Mul<BaseField, Output = Self::F>
72 + Add<SecureField, Output = Self::EF>
73 + Mul<SecureField, Output = Self::EF>
74 + Neg<Output = Self::F>
75 + From<BaseField>;
76
77 type EF: One
80 + Clone
81 + Debug
82 + Zero
83 + Neg<Output = Self::EF>
84 + AddAssign
85 + Add<BaseField, Output = Self::EF>
86 + Mul<BaseField, Output = Self::EF>
87 + Add<SecureField, Output = Self::EF>
88 + Sub<SecureField, Output = Self::EF>
89 + Mul<SecureField, Output = Self::EF>
90 + Add<Self::F, Output = Self::EF>
91 + Mul<Self::F, Output = Self::EF>
92 + Sub<Self::EF, Output = Self::EF>
93 + Mul<Self::EF, Output = Self::EF>
94 + From<SecureField>
95 + From<Self::F>;
96
97 fn next_trace_mask(&mut self) -> Self::F {
99 let [mask_item] = self.next_interaction_mask(ORIGINAL_TRACE_IDX, [0]);
100 mask_item
101 }
102
103 fn get_preprocessed_column(&mut self, _column: PreProcessedColumnId) -> Self::F {
104 let [mask_item] = self.next_interaction_mask(PREPROCESSED_TRACE_IDX, [0]);
105 mask_item
106 }
107
108 fn next_interaction_mask<const N: usize>(
110 &mut self,
111 interaction: usize,
112 offsets: [isize; N],
113 ) -> [Self::F; N];
114
115 fn next_extension_interaction_mask<const N: usize>(
118 &mut self,
119 interaction: usize,
120 offsets: [isize; N],
121 ) -> [Self::EF; N] {
122 let mut res_col_major =
123 array::from_fn(|_| self.next_interaction_mask(interaction, offsets).into_iter());
124 array::from_fn(|_| {
125 Self::combine_ef(res_col_major.each_mut().map(|iter| iter.next().unwrap()))
126 })
127 }
128
129 fn add_constraint<G>(&mut self, constraint: G)
131 where
132 Self::EF: Mul<G, Output = Self::EF> + From<G>;
133
134 fn add_intermediate(&mut self, val: Self::F) -> Self::F {
137 val
138 }
139
140 fn add_extension_intermediate(&mut self, val: Self::EF) -> Self::EF {
143 val
144 }
145
146 fn combine_ef(values: [Self::F; SECURE_EXTENSION_DEGREE]) -> Self::EF;
148
149 fn add_to_relation<R: Relation<Self::F, Self::EF>>(
154 &mut self,
155 entry: RelationEntry<'_, Self::F, Self::EF, R>,
156 ) {
157 let frac = Fraction::new(
158 entry.multiplicity.clone(),
159 entry.relation.combine(entry.values),
160 );
161 self.write_logup_frac(frac);
162 }
163
164 fn write_logup_frac(&mut self, _fraction: Fraction<Self::EF, Self::EF>) {
166 unimplemented!()
167 }
168 fn finalize_logup_batched(&mut self, _batching: &Batching) {
169 unimplemented!()
170 }
171
172 fn finalize_logup(&mut self) {
173 unimplemented!();
174 }
175
176 fn finalize_logup_in_pairs(&mut self) {
177 unimplemented!();
178 }
179}
180
181macro_rules! logup_proxy {
185 () => {
186 fn write_logup_frac(&mut self, fraction: Fraction<Self::EF, Self::EF>) {
187 if self.logup.fracs.is_empty() {
188 self.logup.is_finalized = false;
189 }
190 self.logup.fracs.push(fraction.clone());
191 }
192
193 fn finalize_logup_batched(&mut self, batching: &crate::Batching) {
197 assert!(!self.logup.is_finalized, "LogupAtRow was already finalized");
198 assert_eq!(
199 batching.len(),
200 self.logup.fracs.len(),
201 "Batching must be of the same length as the number of entries"
202 );
203
204 let last_batch = *batching.iter().max().unwrap();
205
206 let mut fracs_by_batch =
207 hashbrown::HashMap::<usize, std_shims::Vec<Fraction<Self::EF, Self::EF>>>::new();
208
209 for (batch, frac) in batching.iter().zip(self.logup.fracs.iter()) {
210 fracs_by_batch
211 .entry(*batch)
212 .or_insert_with(std_shims::Vec::new)
213 .push(frac.clone());
214 }
215
216 let keys_set: hashbrown::HashSet<_> = fracs_by_batch.keys().cloned().collect();
217 let all_batches_set: hashbrown::HashSet<_> = (0..last_batch + 1).collect();
218
219 assert_eq!(
220 keys_set, all_batches_set,
221 "Batching must contain all consecutive batches"
222 );
223
224 let mut prev_col_cumsum = <Self::EF as num_traits::Zero>::zero();
225
226 for batch_id in (0..last_batch) {
228 let cur_frac: Fraction<_, _> = fracs_by_batch[&batch_id].iter().cloned().sum();
229 let [cur_cumsum] =
230 self.next_extension_interaction_mask(self.logup.interaction, [0]);
231 let diff = cur_cumsum.clone() - prev_col_cumsum.clone();
232 prev_col_cumsum = cur_cumsum;
233 self.add_constraint(diff * cur_frac.denominator - cur_frac.numerator);
234 }
235
236 let frac: Fraction<_, _> = fracs_by_batch[&last_batch].clone().into_iter().sum();
237 let [prev_row_cumsum, cur_cumsum] =
238 self.next_extension_interaction_mask(self.logup.interaction, [-1, 0]);
239
240 let diff = cur_cumsum - prev_row_cumsum - prev_col_cumsum.clone();
241 let shifted_diff = diff + self.logup.cumsum_shift.clone();
245
246 self.add_constraint(shifted_diff * frac.denominator - frac.numerator);
247
248 self.logup.is_finalized = true;
249 }
250
251 fn finalize_logup(&mut self) {
253 let batches = (0..self.logup.fracs.len()).collect();
254 self.finalize_logup_batched(&batches)
255 }
256
257 fn finalize_logup_in_pairs(&mut self) {
260 let batches = (0..self.logup.fracs.len()).map(|n| n / 2).collect();
261 self.finalize_logup_batched(&batches)
262 }
263 };
264}
265pub(crate) use logup_proxy;
266
267pub trait RelationEFTraitBound<F: Clone>:
268 Clone + Zero + From<F> + From<SecureField> + Mul<F, Output = Self> + Sub<Self, Output = Self>
269{
270}
271
272impl<F, EF> RelationEFTraitBound<F> for EF
273where
274 F: Clone,
275 EF: Clone + Zero + From<F> + From<SecureField> + Mul<F, Output = EF> + Sub<EF, Output = EF>,
276{
277}
278
279pub trait Relation<F: Clone, EF: RelationEFTraitBound<F>>: Sized {
281 fn combine(&self, values: &[F]) -> EF;
282
283 fn get_name(&self) -> &str;
284 fn get_size(&self) -> usize;
285}
286
287pub struct RelationEntry<'a, F: Clone, EF: RelationEFTraitBound<F>, R: Relation<F, EF>> {
294 relation: &'a R,
295 multiplicity: EF,
296 values: &'a [F],
297}
298impl<'a, F: Clone, EF: RelationEFTraitBound<F>, R: Relation<F, EF>> RelationEntry<'a, F, EF, R> {
299 pub const fn new(relation: &'a R, multiplicity: EF, values: &'a [F]) -> Self {
300 Self {
301 relation,
302 multiplicity,
303 values,
304 }
305 }
306}
307
308#[macro_export]
309macro_rules! relation {
310 ($name:tt, $size:tt) => {
311 #[derive(Clone, Debug, PartialEq)]
312 pub struct $name($crate::logup::LookupElements<$size>);
313
314 #[allow(dead_code)]
315 impl $name {
316 pub fn dummy() -> Self {
317 Self($crate::logup::LookupElements::dummy())
318 }
319 pub fn draw(channel: &mut impl stwo::core::channel::Channel) -> Self {
320 Self($crate::logup::LookupElements::draw(channel))
321 }
322 }
323
324 impl<F: Clone, EF: $crate::RelationEFTraitBound<F>> $crate::Relation<F, EF> for $name {
325 fn combine(&self, values: &[F]) -> EF {
326 self.0.combine(values)
327 }
328
329 fn get_name(&self) -> &str {
330 stringify!($name)
331 }
332
333 fn get_size(&self) -> usize {
334 $size
335 }
336 }
337 };
338}
339
340#[cfg(test)]
341#[macro_export]
342macro_rules! m31 {
343 ($m:expr) => {
344 stwo::core::fields::m31::M31::from_u32_unchecked($m)
345 };
346}
347
348#[cfg(test)]
349#[macro_export]
350macro_rules! qm31 {
351 ($m0:expr, $m1:expr, $m2:expr, $m3:expr) => {{
352 stwo::core::fields::qm31::QM31::from_u32_unchecked($m0, $m1, $m2, $m3)
353 }};
354}