1use super::super::MatPolyOverZ;
12use crate::integer::{PolyOverZ, Z};
13use crate::integer_mod_q::{MatPolynomialRingZq, PolynomialRingZq};
14use crate::macros::arithmetics::{
15 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
16 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
17 arithmetic_trait_reverse,
18};
19use crate::macros::for_others::implement_for_others;
20use crate::traits::MatrixDimensions;
21use flint_sys::fmpz_poly_mat::{fmpz_poly_mat_scalar_mul_fmpz, fmpz_poly_mat_scalar_mul_fmpz_poly};
22use std::ops::{Mul, MulAssign};
23
24impl Mul<&Z> for &MatPolyOverZ {
25 type Output = MatPolyOverZ;
26 fn mul(self, scalar: &Z) -> Self::Output {
46 let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
47 unsafe {
48 fmpz_poly_mat_scalar_mul_fmpz(&mut out.matrix, &self.matrix, &scalar.value);
49 }
50 out
51 }
52}
53
54arithmetic_trait_reverse!(Mul, mul, Z, MatPolyOverZ, MatPolyOverZ);
55
56arithmetic_trait_borrowed_to_owned!(Mul, mul, MatPolyOverZ, Z, MatPolyOverZ);
57arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatPolyOverZ, MatPolyOverZ);
58arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatPolyOverZ, Z, MatPolyOverZ);
59arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatPolyOverZ, MatPolyOverZ);
60
61implement_for_others!(Z, MatPolyOverZ, MatPolyOverZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
62
63impl Mul<&PolyOverZ> for &MatPolyOverZ {
64 type Output = MatPolyOverZ;
65 fn mul(self, scalar: &PolyOverZ) -> Self::Output {
85 let mut out = MatPolyOverZ::new(self.get_num_rows(), self.get_num_columns());
86 unsafe {
87 fmpz_poly_mat_scalar_mul_fmpz_poly(&mut out.matrix, &self.matrix, &scalar.poly);
88 }
89 out
90 }
91}
92
93arithmetic_trait_reverse!(Mul, mul, PolyOverZ, MatPolyOverZ, MatPolyOverZ);
94
95arithmetic_trait_borrowed_to_owned!(Mul, mul, MatPolyOverZ, PolyOverZ, MatPolyOverZ);
96arithmetic_trait_borrowed_to_owned!(Mul, mul, PolyOverZ, MatPolyOverZ, MatPolyOverZ);
97arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatPolyOverZ, PolyOverZ, MatPolyOverZ);
98arithmetic_trait_mixed_borrowed_owned!(Mul, mul, PolyOverZ, MatPolyOverZ, MatPolyOverZ);
99
100impl Mul<&PolynomialRingZq> for &MatPolyOverZ {
101 type Output = MatPolynomialRingZq;
102 fn mul(self, scalar: &PolynomialRingZq) -> Self::Output {
124 let mut out =
125 MatPolynomialRingZq::new(self.get_num_rows(), self.get_num_columns(), &scalar.modulus);
126 out.matrix = self * &scalar.poly;
127 out.reduce();
128
129 out
130 }
131}
132
133arithmetic_trait_reverse!(
134 Mul,
135 mul,
136 PolynomialRingZq,
137 MatPolyOverZ,
138 MatPolynomialRingZq
139);
140
141arithmetic_trait_borrowed_to_owned!(
142 Mul,
143 mul,
144 MatPolyOverZ,
145 PolynomialRingZq,
146 MatPolynomialRingZq
147);
148arithmetic_trait_borrowed_to_owned!(
149 Mul,
150 mul,
151 PolynomialRingZq,
152 MatPolyOverZ,
153 MatPolynomialRingZq
154);
155arithmetic_trait_mixed_borrowed_owned!(
156 Mul,
157 mul,
158 MatPolyOverZ,
159 PolynomialRingZq,
160 MatPolynomialRingZq
161);
162arithmetic_trait_mixed_borrowed_owned!(
163 Mul,
164 mul,
165 PolynomialRingZq,
166 MatPolyOverZ,
167 MatPolynomialRingZq
168);
169
170impl MulAssign<&Z> for MatPolyOverZ {
171 fn mul_assign(&mut self, scalar: &Z) {
196 unsafe { fmpz_poly_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
197 }
198}
199
200impl MulAssign<&PolyOverZ> for MatPolyOverZ {
201 fn mul_assign(&mut self, scalar: &PolyOverZ) {
203 unsafe { fmpz_poly_mat_scalar_mul_fmpz_poly(&mut self.matrix, &self.matrix, &scalar.poly) };
204 }
205}
206
207impl MulAssign<i64> for MatPolyOverZ {
208 fn mul_assign(&mut self, scalar: i64) {
210 let scalar = Z::from(scalar);
211 unsafe { fmpz_poly_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
212 }
213}
214
215impl MulAssign<u64> for MatPolyOverZ {
216 fn mul_assign(&mut self, scalar: u64) {
218 let scalar = Z::from(scalar);
219 unsafe { fmpz_poly_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
220 }
221}
222
223arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatPolyOverZ, Z);
224arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatPolyOverZ, PolyOverZ);
225arithmetic_assign_between_types!(MulAssign, mul_assign, MatPolyOverZ, i64, i32 i16 i8);
226arithmetic_assign_between_types!(MulAssign, mul_assign, MatPolyOverZ, u64, u32 u16 u8);
227
228#[cfg(test)]
229mod test_mul_z {
230 use crate::integer::MatPolyOverZ;
231 use crate::integer::Z;
232 use std::str::FromStr;
233
234 #[test]
236 fn borrowed_correctness() {
237 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
238 let mat_2 = mat_1.clone();
239 let mat_3 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
240 let integer = Z::from(2);
241
242 let mat_1 = &mat_1 * &integer;
243 let mat_2 = &integer * &mat_2;
244
245 assert_eq!(mat_3, mat_1);
246 assert_eq!(mat_3, mat_2);
247 }
248
249 #[test]
251 fn owned_correctness() {
252 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
253 let mat_2 = mat_1.clone();
254 let mat_3 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
255 let integer_1 = Z::from(2);
256 let integer_2 = Z::from(2);
257
258 let mat_1 = mat_1 * integer_1;
259 let mat_2 = integer_2 * mat_2;
260
261 assert_eq!(mat_3, mat_1);
262 assert_eq!(mat_3, mat_2);
263 }
264
265 #[test]
267 fn half_correctness() {
268 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
269 let mat_2 = mat_1.clone();
270 let mat_3 = mat_1.clone();
271 let mat_4 = mat_1.clone();
272 let mat_5 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
273 let integer_1 = Z::from(2);
274 let integer_2 = Z::from(2);
275
276 let mat_1 = mat_1 * &integer_1;
277 let mat_2 = &integer_2 * mat_2;
278 let mat_3 = &mat_3 * integer_1;
279 let mat_4 = integer_2 * &mat_4;
280
281 assert_eq!(mat_5, mat_1);
282 assert_eq!(mat_5, mat_2);
283 assert_eq!(mat_5, mat_3);
284 assert_eq!(mat_5, mat_4);
285 }
286
287 #[test]
289 #[allow(clippy::erasing_op)]
290 fn different_types() {
291 let mat_1 = MatPolyOverZ::from_str("[[1 42],[0],[2 1 2]]").unwrap();
292 let mat_2 = MatPolyOverZ::from_str("[[1 2, 1 6, 1 5],[1 4, 2 17 42, 1 3]]").unwrap();
293 let mat_3 = MatPolyOverZ::from_str("[[1 84],[0],[2 2 4]]").unwrap();
294 let mat_4 = MatPolyOverZ::from_str("[[0],[0],[0]]").unwrap();
295 let mat_5 = MatPolyOverZ::from_str("[[1 -42],[0],[2 -1 -2]]").unwrap();
296 let mat_6 =
297 MatPolyOverZ::from_str("[[1 4, 1 12, 1 10],[1 8, 2 34 84, 1 6]]").unwrap();
298
299 assert_eq!(mat_3, 2 * &mat_1);
300 assert_eq!(mat_4, 0 * &mat_1);
301 assert_eq!(mat_5, -1 * mat_1);
302 assert_eq!(mat_6, mat_2 * 2);
303 }
304
305 #[test]
307 fn different_dimensions_correctness() {
308 let mat_1 = MatPolyOverZ::from_str("[[1 42],[0],[2 1 2]]").unwrap();
309 let mat_2 = MatPolyOverZ::from_str("[[1 2, 1 6, 1 5],[1 4, 2 17 42, 1 3]]").unwrap();
310 let mat_3 = MatPolyOverZ::from_str("[[1 84],[0],[2 2 4]]").unwrap();
311 let mat_4 =
312 MatPolyOverZ::from_str("[[1 4, 1 12, 1 10],[1 8, 2 34 84, 1 6]]").unwrap();
313 let integer = Z::from(2);
314
315 assert_eq!(mat_3, &integer * mat_1);
316 assert_eq!(mat_4, integer * mat_2);
317 }
318
319 #[test]
321 fn large_entries() {
322 let mat_1 = MatPolyOverZ::from_str(&format!("[[1 1],[1 {}],[1 4]]", i64::MAX)).unwrap();
323 let mat_2 = MatPolyOverZ::from_str("[[1 3]]").unwrap();
324 let mat_3 =
325 MatPolyOverZ::from_str(&format!("[[1 3],[1 {}],[1 12]]", 3 * i64::MAX as i128))
326 .unwrap();
327 let mat_4 = MatPolyOverZ::from_str(&format!("[[1 {}]]", 3 * i64::MAX as i128)).unwrap();
328 let integer_1 = Z::from(3);
329 let integer_2 = Z::from(i64::MAX);
330
331 assert_eq!(mat_3, integer_1 * mat_1);
332 assert_eq!(mat_4, integer_2 * mat_2);
333 }
334}
335
336#[cfg(test)]
337mod test_mul_poly_over_z {
338 use crate::integer::MatPolyOverZ;
339 use crate::integer::PolyOverZ;
340 use std::str::FromStr;
341
342 #[test]
344 fn borrowed_correctness() {
345 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
346 let mat_2 = mat_1.clone();
347 let mat_3 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
348 let scalar = PolyOverZ::from(2);
349
350 let mat_1 = &mat_1 * &scalar;
351 let mat_2 = &scalar * &mat_2;
352
353 assert_eq!(mat_3, mat_1);
354 assert_eq!(mat_3, mat_2);
355 }
356
357 #[test]
359 fn owned_correctness() {
360 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
361 let mat_2 = mat_1.clone();
362 let mat_3 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
363 let scalar_1 = PolyOverZ::from(2);
364 let scalar_2 = PolyOverZ::from(2);
365
366 let mat_1 = mat_1 * scalar_1;
367 let mat_2 = scalar_2 * mat_2;
368
369 assert_eq!(mat_3, mat_1);
370 assert_eq!(mat_3, mat_2);
371 }
372
373 #[test]
375 fn half_correctness() {
376 let mat_1 = MatPolyOverZ::from_str("[[2 1 42, 1 17],[1 8, 2 1 2]]").unwrap();
377 let mat_2 = mat_1.clone();
378 let mat_3 = mat_1.clone();
379 let mat_4 = mat_1.clone();
380 let mat_5 = MatPolyOverZ::from_str("[[2 2 84, 1 34],[1 16, 2 2 4]]").unwrap();
381 let scalar_1 = PolyOverZ::from(2);
382 let scalar_2 = PolyOverZ::from(2);
383
384 let mat_1 = mat_1 * &scalar_1;
385 let mat_2 = &scalar_2 * mat_2;
386 let mat_3 = &mat_3 * scalar_1;
387 let mat_4 = scalar_2 * &mat_4;
388
389 assert_eq!(mat_5, mat_1);
390 assert_eq!(mat_5, mat_2);
391 assert_eq!(mat_5, mat_3);
392 assert_eq!(mat_5, mat_4);
393 }
394
395 #[test]
397 fn different_dimensions_correctness() {
398 let mat_1 = MatPolyOverZ::from_str("[[1 42],[0],[2 1 2]]").unwrap();
399 let mat_2 = MatPolyOverZ::from_str("[[1 2, 1 6, 1 5],[1 4, 2 17 42, 1 3]]").unwrap();
400 let mat_3 = MatPolyOverZ::from_str("[[1 84],[0],[2 2 4]]").unwrap();
401 let mat_4 =
402 MatPolyOverZ::from_str("[[1 4, 1 12, 1 10],[1 8, 2 34 84, 1 6]]").unwrap();
403 let scalar = PolyOverZ::from(2);
404
405 assert_eq!(mat_3, &scalar * mat_1);
406 assert_eq!(mat_4, scalar * mat_2);
407 }
408
409 #[test]
411 fn large_entries() {
412 let mat_1 = MatPolyOverZ::from_str(&format!("[[1 1],[1 {}],[1 4]]", i64::MAX)).unwrap();
413 let mat_2 = MatPolyOverZ::from_str("[[1 3]]").unwrap();
414 let mat_3 =
415 MatPolyOverZ::from_str(&format!("[[1 3],[1 {}],[1 12]]", 3 * i64::MAX as i128))
416 .unwrap();
417 let mat_4 = MatPolyOverZ::from_str(&format!("[[1 {}]]", 3 * i64::MAX as i128)).unwrap();
418 let scalar_1 = PolyOverZ::from(3);
419 let scalar_2 = PolyOverZ::from(i64::MAX);
420
421 assert_eq!(mat_3, scalar_1 * mat_1);
422 assert_eq!(mat_4, scalar_2 * mat_2);
423 }
424}
425
426#[cfg(test)]
427mod test_mul_poly_ring_zq {
428 use crate::integer::MatPolyOverZ;
429 use crate::integer::PolyOverZ;
430 use crate::integer_mod_q::MatPolynomialRingZq;
431 use crate::integer_mod_q::ModulusPolynomialRingZq;
432 use crate::integer_mod_q::PolynomialRingZq;
433 use std::str::FromStr;
434
435 #[test]
437 fn availability() {
438 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
439 let poly_mat = MatPolyOverZ::from_str("[[3 0 1 1, 1 3],[0, 2 1 2]]").unwrap();
440 let poly = PolyOverZ::from_str("2 1 1").unwrap();
441 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
442
443 let _ = &poly_mat * &poly_ring;
444 let _ = &poly_mat * poly_ring.clone();
445 let _ = poly_mat.clone() * &poly_ring;
446 let _ = poly_mat.clone() * poly_ring.clone();
447
448 let _ = &poly_ring * &poly_mat;
449 let _ = &poly_ring * poly_mat.clone();
450 let _ = poly_ring.clone() * &poly_mat;
451 let _ = poly_ring * poly_mat;
452 }
453
454 #[test]
456 fn mul_correctness() {
457 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
458 let poly_mat1 = MatPolyOverZ::from_str("[[2 1 1, 1 3],[0, 2 1 2]]").unwrap();
459 let poly = PolyOverZ::from_str("2 1 1").unwrap();
460 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
461
462 let poly_ring_mat2 = &poly_mat1 * &poly_ring;
463
464 let cmp_poly_mat = MatPolyOverZ::from_str("[[3 1 2 1, 2 3 3],[0, 3 1 3 2]]").unwrap();
465 let cmp_poly_ring_mat = MatPolynomialRingZq::from((&cmp_poly_mat, &modulus));
466
467 assert_eq!(cmp_poly_ring_mat, poly_ring_mat2);
468 }
469
470 #[test]
472 fn reduction_correct() {
473 let modulus = ModulusPolynomialRingZq::from_str("4 2 0 0 2 mod 17").unwrap();
474 let poly_mat1 = MatPolyOverZ::from_str("[[0, 1 10],[0, 2 1 2]]").unwrap();
475 let poly = PolyOverZ::from(2);
476 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
477
478 let poly_ring_mat2 = &poly_mat1 * &poly_ring;
479
480 let cmp_poly_mat = MatPolyOverZ::from_str("[[0, 1 3],[0, 2 2 4]]").unwrap();
481 let cmp_poly_ring_mat = MatPolynomialRingZq::from((&cmp_poly_mat, &modulus));
482
483 assert_eq!(cmp_poly_ring_mat, poly_ring_mat2);
484 }
485
486 #[test]
488 fn different_dimensions_correctness() {
489 let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
490 let poly_mat1 = MatPolyOverZ::from_str("[[1 42],[0],[2 1 2]]").unwrap();
491 let poly_mat2 = MatPolyOverZ::from_str("[[1 2,1 6,1 5],[1 4,2 17 42,1 3]]").unwrap();
492
493 let cmp_poly_mat1 = MatPolyOverZ::from_str("[[1 84],[0],[2 2 4]]").unwrap();
494 let cmp_poly_ring_mat1 = MatPolynomialRingZq::from((&cmp_poly_mat1, &modulus));
495 let cmp_poly_mat2 =
496 MatPolyOverZ::from_str("[[1 4,1 12,1 10],[1 8,2 34 84,1 6]]").unwrap();
497 let cmp_poly_ring_mat2 = MatPolynomialRingZq::from((&cmp_poly_mat2, &modulus));
498 let poly = PolyOverZ::from(2);
499 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
500
501 assert_eq!(cmp_poly_ring_mat1, &poly_mat1 * &poly_ring);
502 assert_eq!(cmp_poly_ring_mat2, &poly_mat2 * &poly_ring);
503 }
504
505 #[test]
507 fn large_entries() {
508 let modulus =
509 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
510 let poly_mat1 =
511 MatPolyOverZ::from_str(&format!("[[1 1],[1 {}],[1 4]]", i64::MAX)).unwrap();
512 let poly_mat2 = MatPolyOverZ::from_str("[[1 3]]").unwrap();
513 let poly1 = PolyOverZ::from(3);
514 let poly_ring1 = PolynomialRingZq::from((&poly1, &modulus));
515 let poly2 = PolyOverZ::from(i64::MAX);
516 let poly_ring2 = PolynomialRingZq::from((&poly2, &modulus));
517
518 let cmp_poly_mat1 =
519 MatPolyOverZ::from_str(&format!("[[1 3],[1 {}],[1 12]]", 3 * i64::MAX as i128))
520 .unwrap();
521 let cmp_poly_ring_mat1 = MatPolynomialRingZq::from((&cmp_poly_mat1, &modulus));
522 let cmp_poly_mat2 =
523 MatPolyOverZ::from_str(&format!("[[1 {}]]", 3 * i64::MAX as i128)).unwrap();
524 let cmp_poly_ring_mat2 = MatPolynomialRingZq::from((&cmp_poly_mat2, &modulus));
525
526 assert_eq!(cmp_poly_ring_mat1, &poly_mat1 * &poly_ring1);
527 assert_eq!(cmp_poly_ring_mat2, &poly_mat2 * &poly_ring2);
528 }
529}
530
531#[cfg(test)]
532mod test_mul_assign {
533 use crate::integer::{MatPolyOverZ, PolyOverZ, Z};
534 use std::str::FromStr;
535
536 #[test]
538 fn consistency() {
539 let mut a = MatPolyOverZ::from_str("[[2 2 1, 1 -2],[0, 2 2 -1]]").unwrap();
540 let b = i32::MAX;
541 let cmp = &a * b;
542
543 a *= b;
544
545 assert_eq!(cmp, a);
546 }
547
548 #[test]
550 fn availability() {
551 let mut a = MatPolyOverZ::from_str("[[2 2 1, 1 -3],[0, 2 3 1]]").unwrap();
552 let b = Z::from(2);
553 let c = PolyOverZ::from_str("2 3 1").unwrap();
554
555 a *= &b;
556 a *= b;
557 a *= &c;
558 a *= c;
559 a *= 1_u8;
560 a *= 1_u16;
561 a *= 1_u32;
562 a *= 1_u64;
563 a *= 1_i8;
564 a *= 1_i16;
565 a *= 1_i32;
566 a *= 1_i64;
567 }
568}