1use super::super::MatZq;
12use crate::error::MathError;
13use crate::integer::Z;
14use crate::integer_mod_q::Zq;
15use crate::macros::arithmetics::{
16 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
17 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
18 arithmetic_trait_reverse,
19};
20use crate::macros::for_others::implement_for_others;
21use crate::traits::{CompareBase, MatrixDimensions};
22use flint_sys::fmpz_mod_mat::{
23 fmpz_mod_mat_scalar_mul_fmpz, fmpz_mod_mat_scalar_mul_si, fmpz_mod_mat_scalar_mul_ui,
24};
25use std::ops::{Mul, MulAssign};
26
27impl Mul<&Z> for &MatZq {
28 type Output = MatZq;
29 fn mul(self, scalar: &Z) -> Self::Output {
49 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
50 unsafe {
51 fmpz_mod_mat_scalar_mul_fmpz(&mut out.matrix, &self.matrix, &scalar.value);
52 }
53 out
54 }
55}
56
57arithmetic_trait_reverse!(Mul, mul, Z, MatZq, MatZq);
58
59arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZq, Z, MatZq);
60arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZq, MatZq);
61arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZq, Z, MatZq);
62arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatZq, MatZq);
63
64implement_for_others!(Z, MatZq, MatZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
65
66impl Mul<&Zq> for &MatZq {
67 type Output = MatZq;
68 fn mul(self, scalar: &Zq) -> Self::Output {
90 self.mul_scalar_safe(scalar).unwrap()
91 }
92}
93
94arithmetic_trait_reverse!(Mul, mul, Zq, MatZq, MatZq);
95
96arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZq, Zq, MatZq);
97arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, MatZq, MatZq);
98arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZq, Zq, MatZq);
99arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, MatZq, MatZq);
100
101impl MatZq {
102 pub fn mul_scalar_safe(&self, scalar: &Zq) -> Result<Self, MathError> {
125 if !self.compare_base(scalar) {
126 return Err(self.call_compare_base_error(scalar).unwrap());
127 }
128
129 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
130 unsafe {
131 fmpz_mod_mat_scalar_mul_fmpz(&mut out.matrix, &self.matrix, &scalar.value.value);
132 }
133 Ok(out)
134 }
135}
136
137impl MulAssign<&Z> for MatZq {
138 fn mul_assign(&mut self, scalar: &Z) {
164 unsafe { fmpz_mod_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
165 }
166}
167
168impl MulAssign<&Zq> for MatZq {
169 fn mul_assign(&mut self, scalar: &Zq) {
174 if !self.compare_base(scalar) {
175 panic!("{}", self.call_compare_base_error(scalar).unwrap())
176 }
177 unsafe {
178 fmpz_mod_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value.value)
179 };
180 }
181}
182
183arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatZq, Zq);
184
185impl MulAssign<i64> for MatZq {
186 fn mul_assign(&mut self, other: i64) {
188 unsafe { fmpz_mod_mat_scalar_mul_si(&mut self.matrix, &self.matrix, other) };
189 }
190}
191
192impl MulAssign<u64> for MatZq {
193 fn mul_assign(&mut self, other: u64) {
195 unsafe { fmpz_mod_mat_scalar_mul_ui(&mut self.matrix, &self.matrix, other) };
196 }
197}
198
199arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatZq, Z);
200arithmetic_assign_between_types!(MulAssign, mul_assign, MatZq, i64, i32 i16 i8);
201arithmetic_assign_between_types!(MulAssign, mul_assign, MatZq, u64, u32 u16 u8);
202
203#[cfg(test)]
204mod test_mul_z {
205 use crate::integer::Z;
206 use crate::integer_mod_q::MatZq;
207 use std::str::FromStr;
208
209 #[test]
211 fn borrowed_correctness() {
212 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
213 let mat_2 = mat_1.clone();
214 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
215 let integer = Z::from(2);
216
217 let mat_1 = &mat_1 * &integer;
218 let mat_2 = &integer * &mat_2;
219
220 assert_eq!(mat_3, mat_1);
221 assert_eq!(mat_3, mat_2);
222 }
223
224 #[test]
226 fn owned_correctness() {
227 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
228 let mat_2 = mat_1.clone();
229 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
230 let integer_1 = Z::from(2);
231 let integer_2 = Z::from(2);
232
233 let mat_1 = mat_1 * integer_1;
234 let mat_2 = integer_2 * mat_2;
235
236 assert_eq!(mat_3, mat_1);
237 assert_eq!(mat_3, mat_2);
238 }
239
240 #[test]
242 fn half_correctness() {
243 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
244 let mat_2 = mat_1.clone();
245 let mat_3 = mat_1.clone();
246 let mat_4 = mat_1.clone();
247 let mat_5 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
248 let integer_1 = Z::from(2);
249 let integer_2 = Z::from(2);
250
251 let mat_1 = mat_1 * &integer_1;
252 let mat_2 = &integer_2 * mat_2;
253 let mat_3 = &mat_3 * integer_1;
254 let mat_4 = integer_2 * &mat_4;
255
256 assert_eq!(mat_5, mat_1);
257 assert_eq!(mat_5, mat_2);
258 assert_eq!(mat_5, mat_3);
259 assert_eq!(mat_5, mat_4);
260 }
261
262 #[test]
264 #[allow(clippy::erasing_op)]
265 fn different_types() {
266 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
267 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
268 let mat_3 = MatZq::from_str("[[23],[0],[4]] mod 61").unwrap();
269 let mat_4 = MatZq::from_str("[[0],[0],[0]] mod 61").unwrap();
270 let mat_5 = MatZq::from_str("[[-42],[0],[-2]] mod 61").unwrap();
271 let mat_6 = MatZq::from_str("[[6, 18, 15],[12, 126, 9]] mod 61").unwrap();
272
273 assert_eq!(mat_3, 2u8 * &mat_1);
274 assert_eq!(mat_3, 2i8 * &mat_1);
275 assert_eq!(mat_3, 2u16 * &mat_1);
276 assert_eq!(mat_3, 2i16 * &mat_1);
277 assert_eq!(mat_3, 2u32 * &mat_1);
278 assert_eq!(mat_3, 2i32 * &mat_1);
279 assert_eq!(mat_3, 2u64 * &mat_1);
280 assert_eq!(mat_3, 2i64 * &mat_1);
281 assert_eq!(mat_4, 0 * &mat_1);
282 assert_eq!(mat_5, -1 * mat_1);
283 assert_eq!(mat_6, mat_2 * 3);
284 }
285
286 #[test]
288 fn different_dimensions_correctness() {
289 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
290 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
291 let mat_3 = MatZq::from_str("[[84],[0],[4]] mod 61").unwrap();
292 let mat_4 = MatZq::from_str("[[4, 12, 10],[8, 84, 6]] mod 61").unwrap();
293 let integer = Z::from(2);
294
295 assert_eq!(mat_3, &integer * mat_1);
296 assert_eq!(mat_4, integer * mat_2);
297 }
298
299 #[test]
301 fn large_entries() {
302 let mat_1 = MatZq::from_str(&format!("[[1],[{}],[4]] mod {}", i64::MAX, u64::MAX)).unwrap();
303 let mat_2 = MatZq::from_str(&format!("[[3]] mod {}", u64::MAX)).unwrap();
304 let mat_3 =
305 MatZq::from_str(&format!("[[3],[{}],[12]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
306 let mat_4 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
307 let integer_1 = Z::from(3);
308 let integer_2 = Z::from(i64::MAX);
309
310 assert_eq!(mat_3, integer_1 * mat_1);
311 assert_eq!(mat_4, integer_2 * mat_2);
312 }
313}
314
315#[cfg(test)]
316mod test_mul_zq {
317 use crate::integer_mod_q::{MatZq, Zq};
318 use std::str::FromStr;
319
320 #[test]
322 fn borrowed_correctness() {
323 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
324 let mat_2 = mat_1.clone();
325 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
326 let integer = Zq::from((2, 61));
327
328 let mat_1 = &mat_1 * &integer;
329 let mat_2 = &integer * &mat_2;
330
331 assert_eq!(mat_3, mat_1);
332 assert_eq!(mat_3, mat_2);
333 }
334
335 #[test]
337 fn owned_correctness() {
338 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
339 let mat_2 = mat_1.clone();
340 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
341 let integer_1 = Zq::from((2, 61));
342 let integer_2 = Zq::from((2, 61));
343
344 let mat_1 = mat_1 * integer_1;
345 let mat_2 = integer_2 * mat_2;
346
347 assert_eq!(mat_3, mat_1);
348 assert_eq!(mat_3, mat_2);
349 }
350
351 #[test]
353 fn half_correctness() {
354 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
355 let mat_2 = mat_1.clone();
356 let mat_3 = mat_1.clone();
357 let mat_4 = mat_1.clone();
358 let mat_5 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
359 let integer_1 = Zq::from((2, 61));
360 let integer_2 = Zq::from((2, 61));
361
362 let mat_1 = mat_1 * &integer_1;
363 let mat_2 = &integer_2 * mat_2;
364 let mat_3 = &mat_3 * integer_1;
365 let mat_4 = integer_2 * &mat_4;
366
367 assert_eq!(mat_5, mat_1);
368 assert_eq!(mat_5, mat_2);
369 assert_eq!(mat_5, mat_3);
370 assert_eq!(mat_5, mat_4);
371 }
372
373 #[test]
375 fn different_dimensions_correctness() {
376 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
377 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
378 let mat_3 = MatZq::from_str("[[84],[0],[4]] mod 61").unwrap();
379 let mat_4 = MatZq::from_str("[[4, 12, 10],[8, 84, 6]] mod 61").unwrap();
380 let integer = Zq::from((2, 61));
381
382 assert_eq!(mat_3, &integer * mat_1);
383 assert_eq!(mat_4, integer * mat_2);
384 }
385
386 #[test]
388 fn large_entries() {
389 let mat_1 = MatZq::from_str(&format!("[[1],[{}],[4]] mod {}", i64::MAX, u64::MAX)).unwrap();
390 let mat_2 = MatZq::from_str(&format!("[[3]] mod {}", u64::MAX)).unwrap();
391 let mat_3 =
392 MatZq::from_str(&format!("[[3],[{}],[12]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
393 let mat_4 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
394 let integer_1 = Zq::from((3, u64::MAX));
395 let integer_2 = Zq::from((i64::MAX, u64::MAX));
396
397 assert_eq!(mat_3, integer_1 * mat_1);
398 assert_eq!(mat_4, integer_2 * mat_2);
399 }
400
401 #[test]
403 #[should_panic]
404 fn different_moduli_error() {
405 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
406 let integer = Zq::from((2, 3));
407
408 _ = &integer * mat_1;
409 }
410
411 #[test]
413 fn different_moduli_error_safe() {
414 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
415 let integer = Zq::from((2, 3));
416
417 let mat_2 = &mat_1.mul_scalar_safe(&integer);
418
419 assert!(mat_2.is_err());
420 }
421}
422
423#[cfg(test)]
424mod test_mul_assign {
425 use crate::integer::Z;
426 use crate::integer_mod_q::{MatZq, Zq};
427 use std::str::FromStr;
428
429 #[test]
431 fn consistency() {
432 let mut a = MatZq::from_str(&format!("[[2, 1],[-1, 0]] mod {}", u64::MAX - 1)).unwrap();
433 let b = i32::MAX;
434 let cmp = &a * b;
435
436 a *= b;
437
438 assert_eq!(cmp, a);
439 }
440
441 #[test]
443 fn availability() {
444 let mut mat_zq = MatZq::from_str("[[2, 1],[1, 2]] mod 7").unwrap();
445 let z = Z::from(2);
446 let zq = Zq::from((2, 7));
447
448 mat_zq *= &z;
449 mat_zq *= z;
450 mat_zq *= &zq;
451 mat_zq *= zq;
452 mat_zq *= 1_u8;
453 mat_zq *= 1_u16;
454 mat_zq *= 1_u32;
455 mat_zq *= 1_u64;
456 mat_zq *= 1_i8;
457 mat_zq *= 1_i16;
458 mat_zq *= 1_i32;
459 mat_zq *= 1_i64;
460 }
461
462 #[test]
464 #[should_panic]
465 fn mismatching_modulus_zq() {
466 let mut mat_zq = MatZq::from_str("[[2, 1],[1, 2]] mod 7").unwrap();
467
468 let zq = Zq::from((2, u64::MAX - 1));
469
470 mat_zq *= &zq;
471 }
472}