|
9 | 9 | //! Implementation to set elements of a [`MatPolynomialRingZq`] matrix. |
10 | 10 |
|
11 | 11 | use super::MatPolynomialRingZq; |
12 | | -use crate::integer_mod_q::PolynomialRingZq; |
| 12 | +use crate::integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolynomialRingZq}; |
13 | 13 | use crate::macros::for_others::implement_for_owned; |
14 | 14 | use crate::traits::{MatrixSetSubmatrix, MatrixSwaps}; |
15 | 15 | use crate::{error::MathError, integer::PolyOverZ, traits::MatrixSetEntry}; |
@@ -381,6 +381,60 @@ impl MatPolynomialRingZq { |
381 | 381 | pub fn reverse_rows(&mut self) { |
382 | 382 | self.matrix.reverse_rows() |
383 | 383 | } |
| 384 | + |
| 385 | + /// Changes the modulus of the given matrix to the new modulus. |
| 386 | + /// It takes the representation of each entry with coefficients in [0, q) as the new |
| 387 | + /// matrix entries and reduces them by the new [`ModulusPolynomialRingZq`]. |
| 388 | + /// |
| 389 | + /// Parameters: |
| 390 | + /// - `modulus`: the new modulus of the matrix |
| 391 | + /// |
| 392 | + /// # Examples |
| 393 | + /// ``` |
| 394 | + /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}; |
| 395 | + /// use std::str::FromStr; |
| 396 | + /// let modulus0 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap(); |
| 397 | + /// let modulus1 = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 19").unwrap(); |
| 398 | + /// |
| 399 | + /// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus0); |
| 400 | + /// |
| 401 | + /// matrix.change_modulus(modulus1); |
| 402 | + /// ``` |
| 403 | + /// |
| 404 | + /// # Panics ... |
| 405 | + /// - if `modulus` is smaller than `2`, or |
| 406 | + /// - if the modulus polynomial is of degree smaller than `1`. |
| 407 | + /// - if the leading coefficient is not `1.` |
| 408 | + pub fn change_modulus(&mut self, modulus: impl Into<ModulusPolynomialRingZq>) { |
| 409 | + self.modulus = modulus.into(); |
| 410 | + self.reduce(); |
| 411 | + } |
| 412 | + |
| 413 | + /// Changes the modulus `q` of the given matrix to the new modulus `q`. |
| 414 | + /// It takes the representation of each entry with coefficients in `[0, q)` as the new |
| 415 | + /// matrix entries and reduces them by the new [`Modulus`]. |
| 416 | + /// |
| 417 | + /// Parameters: |
| 418 | + /// - `q`: the new modulus of the matrix |
| 419 | + /// |
| 420 | + /// # Examples |
| 421 | + /// ``` |
| 422 | + /// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq}; |
| 423 | + /// use std::str::FromStr; |
| 424 | + /// |
| 425 | + /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap(); |
| 426 | + /// |
| 427 | + /// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus); |
| 428 | + /// |
| 429 | + /// matrix.change_q(19); |
| 430 | + /// ``` |
| 431 | + /// |
| 432 | + /// # Panics ... |
| 433 | + /// - if `modulus` is smaller than `2`. |
| 434 | + pub fn change_q(&mut self, q: impl Into<Modulus>) { |
| 435 | + self.modulus.change_q(q); |
| 436 | + self.reduce(); |
| 437 | + } |
384 | 438 | } |
385 | 439 |
|
386 | 440 | #[cfg(test)] |
@@ -1029,3 +1083,124 @@ mod test_set_submatrix { |
1029 | 1083 | assert!(mat1.set_submatrix(0, 0, &mat2.clone(), 0, 9, 0, 9).is_err()); |
1030 | 1084 | } |
1031 | 1085 | } |
| 1086 | + |
| 1087 | +#[cfg(test)] |
| 1088 | +mod test_change_modulus { |
| 1089 | + use super::MatPolynomialRingZq; |
| 1090 | + use crate::integer_mod_q::ModulusPolynomialRingZq; |
| 1091 | + use std::str::FromStr; |
| 1092 | + |
| 1093 | + /// Ensures that the modulus is changed correctly. |
| 1094 | + #[test] |
| 1095 | + fn modulus_correct() { |
| 1096 | + let mut matrix = MatPolynomialRingZq::from_str( |
| 1097 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7", |
| 1098 | + ) |
| 1099 | + .unwrap(); |
| 1100 | + let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 8").unwrap(); |
| 1101 | + |
| 1102 | + matrix.change_modulus(&modulus); |
| 1103 | + |
| 1104 | + assert_eq!( |
| 1105 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8", |
| 1106 | + matrix.to_string() |
| 1107 | + ); |
| 1108 | + } |
| 1109 | + |
| 1110 | + /// Ensures that the modulus is changed correctly, if the modulus is big. |
| 1111 | + #[test] |
| 1112 | + fn big_modulus_correct() { |
| 1113 | + let mut matrix = MatPolynomialRingZq::from_str(&format!( |
| 1114 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}", |
| 1115 | + i64::MAX |
| 1116 | + )) |
| 1117 | + .unwrap(); |
| 1118 | + let modulus = |
| 1119 | + ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap(); |
| 1120 | + |
| 1121 | + matrix.change_modulus(&modulus); |
| 1122 | + |
| 1123 | + assert_eq!( |
| 1124 | + format!( |
| 1125 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}", |
| 1126 | + u64::MAX |
| 1127 | + ), |
| 1128 | + matrix.to_string() |
| 1129 | + ); |
| 1130 | + } |
| 1131 | + |
| 1132 | + /// Ensures that the matrix is reduced correctly. |
| 1133 | + #[test] |
| 1134 | + fn reduced_correct() { |
| 1135 | + let mut matrix = MatPolynomialRingZq::from_str( |
| 1136 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 4 1 0 0 1]] / 8 1 0 0 0 0 0 0 1 mod 7", |
| 1137 | + ) |
| 1138 | + .unwrap(); |
| 1139 | + let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 2").unwrap(); |
| 1140 | + |
| 1141 | + matrix.change_modulus(&modulus); |
| 1142 | + |
| 1143 | + assert_eq!( |
| 1144 | + "[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2", |
| 1145 | + matrix.to_string() |
| 1146 | + ); |
| 1147 | + } |
| 1148 | +} |
| 1149 | + |
| 1150 | +#[cfg(test)] |
| 1151 | +mod test_change_q { |
| 1152 | + use super::MatPolynomialRingZq; |
| 1153 | + use std::str::FromStr; |
| 1154 | + |
| 1155 | + /// Ensures that the modulus `q` is changed correctly. |
| 1156 | + #[test] |
| 1157 | + fn q_correct() { |
| 1158 | + let mut matrix = MatPolynomialRingZq::from_str( |
| 1159 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7", |
| 1160 | + ) |
| 1161 | + .unwrap(); |
| 1162 | + |
| 1163 | + matrix.change_q(8); |
| 1164 | + |
| 1165 | + assert_eq!( |
| 1166 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8", |
| 1167 | + matrix.to_string() |
| 1168 | + ); |
| 1169 | + } |
| 1170 | + |
| 1171 | + /// Ensures that the modulus `q` is changed correctly, if the modulus is big. |
| 1172 | + #[test] |
| 1173 | + fn big_q_correct() { |
| 1174 | + let mut matrix = MatPolynomialRingZq::from_str(&format!( |
| 1175 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}", |
| 1176 | + i64::MAX |
| 1177 | + )) |
| 1178 | + .unwrap(); |
| 1179 | + |
| 1180 | + matrix.change_q(u64::MAX); |
| 1181 | + |
| 1182 | + assert_eq!( |
| 1183 | + format!( |
| 1184 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}", |
| 1185 | + u64::MAX |
| 1186 | + ), |
| 1187 | + matrix.to_string() |
| 1188 | + ); |
| 1189 | + } |
| 1190 | + |
| 1191 | + /// Ensures that the matrix is reduced correctly. |
| 1192 | + #[test] |
| 1193 | + fn reduced_correct() { |
| 1194 | + let mut matrix = MatPolynomialRingZq::from_str( |
| 1195 | + "[[1 1, 1 2, 1 3],[1 4, 1 5, 4 1 0 0 1]] / 4 1 0 0 1 mod 7", |
| 1196 | + ) |
| 1197 | + .unwrap(); |
| 1198 | + |
| 1199 | + matrix.change_q(2); |
| 1200 | + |
| 1201 | + assert_eq!( |
| 1202 | + "[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2", |
| 1203 | + matrix.to_string() |
| 1204 | + ); |
| 1205 | + } |
| 1206 | +} |
0 commit comments