1use core::borrow::BorrowMut;
2
3use p3_field::{Field, PrimeCharacteristicRing};
4use p3_matrix::Matrix;
5use p3_matrix::dense::{DenseMatrix, DenseStorage, RowMajorMatrix};
6use p3_util::log2_strict_usize;
7use tracing::instrument;
8
9#[instrument(skip_all, fields(dims = %mat.dimensions()))]
15pub fn divide_by_height<F: Field, S: DenseStorage<F> + BorrowMut<[F]>>(
16 mat: &mut DenseMatrix<F, S>,
17) {
18 let h = mat.height();
19 let log_h = log2_strict_usize(h);
20 let h_inv_subfield = F::PrimeSubfield::ONE.div_2exp_u64(log_h as u64);
23 let h_inv = F::from_prime_subfield(h_inv_subfield);
24 mat.scale(h_inv)
25}
26
27pub(crate) fn coset_shift_cols<F: Field>(mat: &mut RowMajorMatrix<F>, shift: F) {
29 mat.rows_mut()
30 .zip(shift.powers())
31 .for_each(|(row, weight)| {
32 row.iter_mut().for_each(|coeff| {
33 *coeff *= weight;
34 });
35 });
36}
37
38#[cfg(test)]
39mod tests {
40 use alloc::vec;
41
42 use p3_baby_bear::BabyBear;
43 use p3_matrix::dense::RowMajorMatrix;
44
45 use super::*;
46
47 type F = BabyBear;
48
49 #[test]
50 fn test_divide_by_height_2x2() {
51 let mut mat = RowMajorMatrix::new(
57 vec![F::from_u8(2), F::from_u8(4), F::from_u8(6), F::from_u8(8)],
58 2,
59 );
60
61 divide_by_height(&mut mat);
62
63 let expected = vec![F::from_u8(1), F::from_u8(2), F::from_u8(3), F::from_u8(4)];
65
66 assert_eq!(mat.values, expected);
67 }
68
69 #[test]
70 fn test_divide_by_height_1x4() {
71 let mut mat = RowMajorMatrix::new_row(vec![
75 F::from_u8(10),
76 F::from_u8(20),
77 F::from_u8(30),
78 F::from_u8(40),
79 ]);
80
81 divide_by_height(&mut mat);
82
83 let expected = vec![
84 F::from_u8(10),
85 F::from_u8(20),
86 F::from_u8(30),
87 F::from_u8(40),
88 ];
89
90 assert_eq!(mat.values, expected);
91 }
92
93 #[test]
94 #[should_panic]
95 fn test_divide_by_height_non_power_of_two_height_should_panic() {
96 let mut mat = RowMajorMatrix::new(vec![F::from_u8(1), F::from_u8(2), F::from_u8(3)], 1);
98
99 divide_by_height(&mut mat);
100 }
101
102 #[test]
103 fn test_coset_shift_cols_3x2_shift_2() {
104 let mut mat = RowMajorMatrix::new(
115 vec![
116 F::from_u8(1),
117 F::from_u8(2),
118 F::from_u8(3),
119 F::from_u8(4),
120 F::from_u8(5),
121 F::from_u8(6),
122 ],
123 2,
124 );
125
126 coset_shift_cols(&mut mat, F::from_u8(2));
127
128 let expected = vec![
129 F::from_u8(1),
130 F::from_u8(2),
131 F::from_u8(6),
132 F::from_u8(8),
133 F::from_u8(20),
134 F::from_u8(24),
135 ];
136
137 assert_eq!(mat.values, expected);
138 }
139
140 #[test]
141 fn test_coset_shift_cols_identity_shift() {
142 let mut mat = RowMajorMatrix::new(
144 vec![F::from_u8(7), F::from_u8(8), F::from_u8(9), F::from_u8(10)],
145 2,
146 );
147
148 coset_shift_cols(&mut mat, F::from_u8(1));
149
150 let expected = vec![F::from_u8(7), F::from_u8(8), F::from_u8(9), F::from_u8(10)];
151
152 assert_eq!(mat.values, expected);
153 }
154}