stwo_gpu/core/poly/
utils.rs1use std_shims::Vec;
2
3use super::line::LineDomain;
4use crate::core::circle::CirclePoint;
5use crate::core::fields::m31::BaseField;
6use crate::core::fields::{ExtensionOf, Field};
7
8pub fn fold<F: Field, E: ExtensionOf<F>>(values: &[F], folding_factors: &[E]) -> E {
28 let n = values.len();
29 assert_eq!(n, 1 << folding_factors.len());
30 if n == 1 {
31 return values[0].into();
32 }
33 let (lhs_values, rhs_values) = values.split_at(n / 2);
34 let (folding_factor, folding_factors) = folding_factors.split_first().unwrap();
35 let lhs_val = fold(lhs_values, folding_factors);
36 let rhs_val = fold(rhs_values, folding_factors);
37 lhs_val + rhs_val * *folding_factor
38}
39
40#[allow(clippy::uninit_vec)]
45pub fn get_folding_alphas<F: Field + ExtensionOf<BaseField>>(
46 point: CirclePoint<F>,
47 len: usize,
48) -> Vec<F> {
49 if len == 0 {
50 return Vec::new();
51 }
52 let mut alphas = Vec::with_capacity(len);
55 unsafe {
56 alphas.set_len(len);
57 }
58
59 alphas[len - 1] = point.y;
61 if len > 1 {
62 let mut x = point.x;
63 for i in (0..len - 1).rev() {
64 alphas[i] = x;
65 x = CirclePoint::double_x(x);
66 }
67 }
68
69 alphas
70}
71
72pub fn repeat_value<T: Copy>(values: &[T], duplicity: usize) -> Vec<T> {
81 let n = values.len();
82 let mut res: Vec<T> = Vec::with_capacity(n * duplicity);
83
84 for &v in values {
86 for _ in 0..duplicity {
87 res.push(v)
88 }
89 }
90
91 res
92}
93
94pub fn domain_line_twiddles_from_tree<T>(
99 domain: impl Into<LineDomain>,
100 twiddle_buffer: &[T],
101) -> Vec<&[T]> {
102 let domain = domain.into();
103 assert!(
104 domain.coset().size() <= twiddle_buffer.len(),
105 "Not enough twiddles!"
106 );
107 (0..domain.coset().log_size())
108 .map(|i| {
109 let len = 1 << i;
110 &twiddle_buffer[twiddle_buffer.len() - len * 2..twiddle_buffer.len() - len]
111 })
112 .rev()
113 .collect()
114}
115
116#[cfg(test)]
117mod tests {
118 use std_shims::vec;
119
120 use super::repeat_value;
121 use crate::core::poly::circle::CanonicCoset;
122 use crate::core::poly::line::LineDomain;
123 use crate::core::poly::utils::domain_line_twiddles_from_tree;
124
125 #[test]
126 fn repeat_value_0_times_works() {
127 assert!(repeat_value(&[1, 2, 3], 0).is_empty());
128 }
129
130 #[test]
131 fn repeat_value_2_times_works() {
132 assert_eq!(repeat_value(&[1, 2, 3], 2), vec![1, 1, 2, 2, 3, 3]);
133 }
134
135 #[test]
136 fn repeat_value_3_times_works() {
137 assert_eq!(repeat_value(&[1, 2], 3), vec![1, 1, 1, 2, 2, 2]);
138 }
139
140 #[test]
141 fn test_domain_line_twiddles_works() {
142 let domain: LineDomain = CanonicCoset::new(4).circle_domain().into();
143 let twiddles = domain_line_twiddles_from_tree(domain, &[0, 1, 2, 3, 4, 5, 6, 7]);
144 assert_eq!(twiddles.len(), 3);
145 assert_eq!(twiddles[0], &[0, 1, 2, 3]);
146 assert_eq!(twiddles[1], &[4, 5]);
147 assert_eq!(twiddles[2], &[6]);
148 }
149
150 #[test]
151 #[should_panic]
152 fn test_domain_line_twiddles_fails() {
153 let domain: LineDomain = CanonicCoset::new(5).circle_domain().into();
154 domain_line_twiddles_from_tree(domain, &[0, 1, 2, 3, 4, 5, 6, 7]);
155 }
156}