@@ -3,6 +3,8 @@ use std::mem::transmute;
3
3
use std:: simd:: Simd ;
4
4
5
5
use bytemuck:: Zeroable ;
6
+ use itertools:: Itertools ;
7
+ use num_traits:: { One , Zero } ;
6
8
#[ cfg( feature = "parallel" ) ]
7
9
use rayon:: prelude:: * ;
8
10
@@ -14,10 +16,11 @@ use crate::core::backend::cpu::circle::slow_precompute_twiddles;
14
16
use crate :: core:: backend:: simd:: column:: BaseColumn ;
15
17
use crate :: core:: backend:: simd:: m31:: PackedM31 ;
16
18
use crate :: core:: backend:: { Col , Column , CpuBackend } ;
17
- use crate :: core:: circle:: { CirclePoint , Coset , M31_CIRCLE_LOG_ORDER } ;
19
+ use crate :: core:: circle:: { CirclePoint , CirclePointIndex , Coset , M31_CIRCLE_LOG_ORDER } ;
20
+ use crate :: core:: constraints:: { coset_vanishing, coset_vanishing_derivative, point_vanishing} ;
18
21
use crate :: core:: fields:: m31:: BaseField ;
19
22
use crate :: core:: fields:: qm31:: SecureField ;
20
- use crate :: core:: fields:: { Field , FieldExpOps } ;
23
+ use crate :: core:: fields:: { batch_inverse_in_place , Field , FieldExpOps } ;
21
24
use crate :: core:: poly:: circle:: {
22
25
CanonicCoset , CircleDomain , CircleEvaluation , CirclePoly , PolyOps ,
23
26
} ;
@@ -221,6 +224,117 @@ impl PolyOps for SimdBackend {
221
224
( sum * twiddle_lows) . pointwise_sum ( )
222
225
}
223
226
227
+ fn weights ( log_size : u32 , sample_point : CirclePoint < SecureField > ) -> Col < Self , SecureField > {
228
+ let domain = CanonicCoset :: new ( log_size) . circle_domain ( ) ;
229
+ let weights_vec_len = domain. size ( ) . div_ceil ( N_LANES ) ;
230
+
231
+ for i in 0 ..domain. size ( ) {
232
+ if domain. at ( i) . into_ef ( ) == sample_point {
233
+ let mut weights = Col :: < Self , SecureField > :: zeros ( domain. size ( ) ) ;
234
+ weights. set ( i, SecureField :: one ( ) ) ;
235
+ return weights;
236
+ }
237
+ }
238
+
239
+ let p_0 = domain. at ( 0 ) . into_ef :: < SecureField > ( ) ;
240
+ let weights_first_half = SecureField :: one ( )
241
+ / ( -( p_0. y + p_0. y )
242
+ * coset_vanishing_derivative (
243
+ Coset :: new ( CirclePointIndex :: generator ( ) , domain. log_size ( ) ) ,
244
+ p_0,
245
+ ) ) ;
246
+ let p_0_inverse = domain. at ( domain. half_coset . size ( ) ) . into_ef :: < SecureField > ( ) ;
247
+ let weights_second_half = SecureField :: one ( )
248
+ / ( -( p_0_inverse. y + p_0_inverse. y )
249
+ * coset_vanishing_derivative (
250
+ Coset :: new ( CirclePointIndex :: generator ( ) , domain. log_size ( ) ) ,
251
+ p_0_inverse,
252
+ ) ) ;
253
+
254
+ let domain_points_vanishing_evaluated_at_point = ( 0 ..weights_vec_len)
255
+ . map ( |i| {
256
+ PackedSecureField :: from_array ( std:: array:: from_fn ( |j| {
257
+ if domain. size ( ) <= i * N_LANES + j {
258
+ SecureField :: one ( )
259
+ } else {
260
+ point_vanishing (
261
+ domain. at ( i * N_LANES + j) . into_ef :: < SecureField > ( ) ,
262
+ sample_point. into_ef :: < SecureField > ( ) ,
263
+ )
264
+ }
265
+ } ) )
266
+ } )
267
+ . collect_vec ( ) ;
268
+ let mut inversed_domain_points_vanishing_evaluated_at_point =
269
+ vec ! [ unsafe { std:: mem:: zeroed( ) } ; weights_vec_len] ;
270
+
271
+ batch_inverse_in_place (
272
+ & domain_points_vanishing_evaluated_at_point,
273
+ & mut inversed_domain_points_vanishing_evaluated_at_point,
274
+ ) ;
275
+
276
+ let coset_vanishing_evaluated_at_point: SecureField = coset_vanishing (
277
+ CanonicCoset :: new ( domain. log_size ( ) ) . coset ,
278
+ sample_point. into_ef :: < SecureField > ( ) ,
279
+ ) ;
280
+
281
+ if weights_vec_len == 1 {
282
+ return ( 0 ..N_LANES )
283
+ . map ( |i| {
284
+ let inversed_domain_points_vanishing_evaluated_at_point =
285
+ inversed_domain_points_vanishing_evaluated_at_point[ 0 ] . to_array ( ) ;
286
+ if i < domain. size ( ) / 2 {
287
+ inversed_domain_points_vanishing_evaluated_at_point[ i]
288
+ * ( weights_first_half * coset_vanishing_evaluated_at_point)
289
+ } else {
290
+ inversed_domain_points_vanishing_evaluated_at_point[ i]
291
+ * ( weights_second_half * coset_vanishing_evaluated_at_point)
292
+ }
293
+ } )
294
+ . collect ( ) ;
295
+ }
296
+
297
+ let weights: Col < Self , SecureField > = ( 0 ..weights_vec_len)
298
+ . map ( |i| {
299
+ if i < weights_vec_len / 2 {
300
+ inversed_domain_points_vanishing_evaluated_at_point[ i]
301
+ * ( weights_first_half * coset_vanishing_evaluated_at_point)
302
+ } else {
303
+ inversed_domain_points_vanishing_evaluated_at_point[ i]
304
+ * ( weights_second_half * coset_vanishing_evaluated_at_point)
305
+ }
306
+ } )
307
+ . collect ( ) ;
308
+
309
+ weights
310
+ }
311
+
312
+ fn barycentric_eval_at_point (
313
+ evals : & CircleEvaluation < Self , BaseField , BitReversedOrder > ,
314
+ point : CirclePoint < SecureField > ,
315
+ weights : & Col < Self , SecureField > ,
316
+ ) -> SecureField {
317
+ for i in 0 ..evals. domain . size ( ) {
318
+ if point == evals. domain . at ( i) . into_ef ( ) {
319
+ return evals
320
+ . values
321
+ . at ( bit_reverse_index ( i, evals. domain . log_size ( ) ) )
322
+ . into ( ) ;
323
+ }
324
+ }
325
+ let evals = evals. clone ( ) . bit_reverse ( ) ;
326
+ if evals. domain . size ( ) < N_LANES {
327
+ return ( 0 ..evals. domain . size ( ) ) . fold ( SecureField :: zero ( ) , |acc, i| {
328
+ acc + ( weights. at ( i) * evals. values . at ( i) )
329
+ } ) ;
330
+ }
331
+ ( 0 ..evals. domain . size ( ) . div_ceil ( N_LANES ) )
332
+ . fold ( PackedSecureField :: zero ( ) , |acc, i| {
333
+ acc + ( weights. data [ i] * evals. values . data [ i] )
334
+ } )
335
+ . pointwise_sum ( )
336
+ }
337
+
224
338
fn extend ( poly : & CirclePoly < Self > , log_size : u32 ) -> CirclePoly < Self > {
225
339
// TODO(shahars): Get rid of extends.
226
340
poly. evaluate ( CanonicCoset :: new ( log_size) . circle_domain ( ) )
0 commit comments