1use super::super::MatZ;
12use crate::integer::Z;
13use crate::integer_mod_q::{MatZq, Zq};
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::rational::{MatQ, Q};
21use crate::traits::MatrixDimensions;
22use flint_sys::fmpz_mat::{
23 fmpz_mat_scalar_mul_fmpz, fmpz_mat_scalar_mul_si, fmpz_mat_scalar_mul_ui,
24};
25use std::ops::{Mul, MulAssign};
26
27impl Mul<&Z> for &MatZ {
28 type Output = MatZ;
29 fn mul(self, scalar: &Z) -> Self::Output {
49 let mut out = MatZ::new(self.get_num_rows(), self.get_num_columns());
50 unsafe {
51 fmpz_mat_scalar_mul_fmpz(&mut out.matrix, &self.matrix, &scalar.value);
52 }
53 out
54 }
55}
56
57arithmetic_trait_reverse!(Mul, mul, Z, MatZ, MatZ);
58
59arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, Z, MatZ);
60arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZ, MatZ);
61arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Z, MatZ);
62arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatZ, MatZ);
63
64implement_for_others!(Z, MatZ, MatZ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
65
66impl Mul<&Q> for &MatZ {
67 type Output = MatQ;
68 fn mul(self, scalar: &Q) -> Self::Output {
88 let out = MatQ::from(self);
89 out * scalar
90 }
91}
92
93arithmetic_trait_reverse!(Mul, mul, Q, MatZ, MatQ);
94
95arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, Q, MatQ);
96arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, MatZ, MatQ);
97arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Q, MatQ);
98arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, MatZ, MatQ);
99
100implement_for_others!(Q, MatZ, MatQ, Mul Scalar for f32 f64);
101
102impl Mul<&Zq> for &MatZ {
103 type Output = MatZq;
104 fn mul(self, scalar: &Zq) -> Self::Output {
124 let out = MatZq::from((self, scalar.get_mod()));
125 out * scalar
126 }
127}
128
129arithmetic_trait_reverse!(Mul, mul, Zq, MatZ, MatZq);
130
131arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, Zq, MatZq);
132arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, MatZ, MatZq);
133arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, Zq, MatZq);
134arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, MatZ, MatZq);
135
136impl MulAssign<&Z> for MatZ {
137 fn mul_assign(&mut self, scalar: &Z) {
159 unsafe { fmpz_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &scalar.value) };
160 }
161}
162
163impl MulAssign<i64> for MatZ {
164 fn mul_assign(&mut self, scalar: i64) {
166 unsafe { fmpz_mat_scalar_mul_si(&mut self.matrix, &self.matrix, scalar) };
167 }
168}
169
170impl MulAssign<u64> for MatZ {
171 fn mul_assign(&mut self, scalar: u64) {
173 unsafe { fmpz_mat_scalar_mul_ui(&mut self.matrix, &self.matrix, scalar) };
174 }
175}
176
177arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatZ, Z);
178arithmetic_assign_between_types!(MulAssign, mul_assign, MatZ, i64, i32 i16 i8);
179arithmetic_assign_between_types!(MulAssign, mul_assign, MatZ, u64, u32 u16 u8);
180
181#[cfg(test)]
182mod test_mul {
183 use super::MatZ;
184 use crate::integer::Z;
185 use std::str::FromStr;
186
187 #[test]
189 fn borrowed_correctness() {
190 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
191 let mat_2 = mat_1.clone();
192 let mat_3 = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
193 let integer = Z::from(3);
194
195 let mat_1 = &mat_1 * &integer;
196 let mat_2 = &integer * &mat_2;
197
198 assert_eq!(mat_3, mat_1);
199 assert_eq!(mat_3, mat_2);
200 }
201
202 #[test]
204 fn owned_correctness() {
205 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
206 let mat_2 = mat_1.clone();
207 let mat_3 = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
208 let integer_1 = Z::from(3);
209 let integer_2 = Z::from(3);
210
211 let mat_1 = mat_1 * integer_1;
212 let mat_2 = integer_2 * mat_2;
213
214 assert_eq!(mat_3, mat_1);
215 assert_eq!(mat_3, mat_2);
216 }
217
218 #[test]
220 fn half_correctness() {
221 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
222 let mat_2 = mat_1.clone();
223 let mat_3 = mat_1.clone();
224 let mat_4 = mat_1.clone();
225 let mat_5 = MatZ::from_str("[[6, 3],[3, 6]]").unwrap();
226 let integer_1 = Z::from(3);
227 let integer_2 = Z::from(3);
228
229 let mat_1 = mat_1 * &integer_1;
230 let mat_2 = &integer_2 * mat_2;
231 let mat_3 = &mat_3 * integer_1;
232 let mat_4 = integer_2 * &mat_4;
233
234 assert_eq!(mat_5, mat_1);
235 assert_eq!(mat_5, mat_2);
236 assert_eq!(mat_5, mat_3);
237 assert_eq!(mat_5, mat_4);
238 }
239
240 #[test]
242 #[allow(clippy::erasing_op)]
243 fn different_types() {
244 let mat_1 = MatZ::from_str("[[1],[0],[4]]").unwrap();
245 let mat_2 = MatZ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
246 let mat_3 = MatZ::from_str("[[2],[0],[8]]").unwrap();
247 let mat_4 = MatZ::from_str("[[0],[0],[0]]").unwrap();
248 let mat_5 = MatZ::from_str("[[-1],[0],[-4]]").unwrap();
249 let mat_6 = MatZ::from_str("[[6, 15, 18],[3, 9, 3]]").unwrap();
250
251 assert_eq!(mat_3, 2 * &mat_1);
252 assert_eq!(mat_4, 0 * &mat_1);
253 assert_eq!(mat_5, -1 * mat_1);
254 assert_eq!(mat_6, mat_2 * 3);
255 }
256
257 #[test]
259 fn different_dimensions_correctness() {
260 let mat_1 = MatZ::from_str("[[1],[0],[4]]").unwrap();
261 let mat_2 = MatZ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
262 let mat_3 = MatZ::from_str("[[3],[0],[12]]").unwrap();
263 let mat_4 = MatZ::from_str("[[6, 15, 18],[3, 9, 3]]").unwrap();
264 let integer = Z::from(3);
265
266 assert_eq!(mat_3, &integer * mat_1);
267 assert_eq!(mat_4, integer * mat_2);
268 }
269
270 #[test]
272 fn large_entries() {
273 let mat_1 = MatZ::from_str(&format!("[[1],[{}],[4]]", i64::MAX)).unwrap();
274 let mat_2 = MatZ::from_str("[[3]]").unwrap();
275 let mat_3 = MatZ::from_str(&format!("[[3],[{}],[12]]", 3 * i64::MAX as i128)).unwrap();
276 let mat_4 = MatZ::from_str(&format!("[[{}]]", 3 * i64::MAX as i128)).unwrap();
277 let integer_1 = Z::from(3);
278 let integer_2 = Z::from(i64::MAX);
279
280 assert_eq!(mat_3, integer_1 * mat_1);
281 assert_eq!(mat_4, integer_2 * mat_2);
282 }
283
284 #[test]
286 fn availability() {
287 let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
288 let integer = Z::from(3);
289
290 let _ = &mat * 1u8;
291 let _ = &mat * 1u16;
292 let _ = &mat * 1u32;
293 let _ = &mat * 1u64;
294 let _ = &mat * 1i8;
295 let _ = &mat * 1i16;
296 let _ = &mat * 1i32;
297 let _ = &mat * 1i64;
298 let _ = &mat * &integer;
299 let _ = &mat * integer;
300 }
301}
302
303#[cfg(test)]
304mod test_mul_q {
305 use super::MatZ;
306 use crate::rational::{MatQ, Q};
307 use std::str::FromStr;
308
309 #[test]
311 fn borrowed_correctness() {
312 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
313 let mat_2 = mat_1.clone();
314 let mat_3 = MatQ::from_str("[[2/3, 1/3],[1/3, 2/3]]").unwrap();
315 let rational = Q::from((1, 3));
316
317 let mat_1 = &mat_1 * &rational;
318 let mat_2 = &rational * &mat_2;
319
320 assert_eq!(mat_3, mat_1);
321 assert_eq!(mat_3, mat_2);
322 }
323
324 #[test]
326 fn owned_correctness() {
327 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
328 let mat_2 = mat_1.clone();
329 let mat_3 = MatQ::from_str("[[2/3, 1/3],[1/3, 2/3]]").unwrap();
330 let rational = Q::from((1, 3));
331
332 let mat_1 = mat_1 * rational.clone();
333 let mat_2 = rational * mat_2;
334
335 assert_eq!(mat_3, mat_1);
336 assert_eq!(mat_3, mat_2);
337 }
338
339 #[test]
341 fn half_correctness() {
342 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
343 let mat_2 = mat_1.clone();
344 let mat_3 = mat_1.clone();
345 let mat_4 = mat_1.clone();
346 let mat_5 = MatQ::from_str("[[2/3, 1/3],[1/3, 2/3]]").unwrap();
347 let rational = Q::from((1, 3));
348
349 let mat_1 = mat_1 * &rational;
350 let mat_2 = &rational * mat_2;
351 let mat_3 = &mat_3 * rational.clone();
352 let mat_4 = rational * &mat_4;
353
354 assert_eq!(mat_5, mat_1);
355 assert_eq!(mat_5, mat_2);
356 assert_eq!(mat_5, mat_3);
357 assert_eq!(mat_5, mat_4);
358 }
359
360 #[test]
362 fn different_dimensions_correctness() {
363 let mat_1 = MatZ::from_str("[[1],[0],[4]]").unwrap();
364 let mat_2 = MatZ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
365 let mat_3 = MatQ::from_str("[[1/3],[0],[4/3]]").unwrap();
366 let mat_4 = MatQ::from_str("[[2/3, 5/3, 6/3],[1/3, 1, 1/3]]").unwrap();
367 let integer = Q::from((1, 3));
368
369 assert_eq!(mat_3, &integer * mat_1);
370 assert_eq!(mat_4, integer * mat_2);
371 }
372
373 #[test]
375 fn large_entries() {
376 let mat_1 = MatZ::from_str(&format!("[[1],[{}],[4]]", i64::MAX)).unwrap();
377 let mat_2 = MatZ::from_str("[[3]]").unwrap();
378 let mat_3 = MatQ::from_str(&format!("[[1/3],[{}/3],[4/3]]", i64::MAX)).unwrap();
379 let mat_4 = MatQ::from_str(&format!("[[3/{}]]", i64::MAX)).unwrap();
380 let rational_1 = Q::from((1, 3));
381 let rational_2 = Q::from((1, i64::MAX));
382
383 assert_eq!(mat_3, rational_1 * mat_1);
384 assert_eq!(mat_4, rational_2 * mat_2);
385 }
386
387 #[test]
389 fn availability() {
390 let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
391 let rational = Q::from(3);
392
393 let _ = &mat * 1.0f32;
394 let _ = &mat * 1.0f64;
395 let _ = &mat * &rational;
396 let _ = &mat * rational;
397 }
398}
399
400#[cfg(test)]
401mod test_mul_zq {
402 use super::MatZ;
403 use crate::integer_mod_q::{MatZq, Zq};
404 use std::str::FromStr;
405
406 #[test]
408 fn borrowed_correctness() {
409 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
410 let mat_2 = mat_1.clone();
411 let mat_3 = MatZq::from_str("[[1, 2],[2, 1]] mod 3").unwrap();
412 let zq = Zq::from((2, 3));
413
414 let mat_1 = &mat_1 * &zq;
415 let mat_2 = &zq * &mat_2;
416
417 assert_eq!(mat_3, mat_1);
418 assert_eq!(mat_3, mat_2);
419 }
420
421 #[test]
423 fn owned_correctness() {
424 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
425 let mat_2 = mat_1.clone();
426 let mat_3 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap();
427 let zq = Zq::from((1, 3));
428
429 let mat_1 = mat_1 * zq.clone();
430 let mat_2 = zq * mat_2;
431
432 assert_eq!(mat_3, mat_1);
433 assert_eq!(mat_3, mat_2);
434 }
435
436 #[test]
438 fn half_correctness() {
439 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
440 let mat_2 = mat_1.clone();
441 let mat_3 = mat_1.clone();
442 let mat_4 = mat_1.clone();
443 let mat_5 = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap();
444 let zq = Zq::from((1, 3));
445
446 let mat_1 = mat_1 * &zq;
447 let mat_2 = &zq * mat_2;
448 let mat_3 = &mat_3 * zq.clone();
449 let mat_4 = zq * &mat_4;
450
451 assert_eq!(mat_5, mat_1);
452 assert_eq!(mat_5, mat_2);
453 assert_eq!(mat_5, mat_3);
454 assert_eq!(mat_5, mat_4);
455 }
456
457 #[test]
459 fn different_dimensions_correctness() {
460 let mat_1 = MatZ::from_str("[[1],[0],[4]]").unwrap();
461 let mat_2 = MatZ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
462 let mat_3 = MatZq::from_str("[[1],[0],[1]] mod 3").unwrap();
463 let mat_4 = MatZq::from_str("[[2, 2, 0],[1, 0, 1]] mod 3").unwrap();
464 let integer = Zq::from((1, 3));
465
466 assert_eq!(mat_3, &integer * mat_1);
467 assert_eq!(mat_4, integer * mat_2);
468 }
469
470 #[test]
472 fn availability() {
473 let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
474 let zq = Zq::from((1, 3));
475
476 let _ = &mat * &zq;
477 let _ = &mat * zq;
478 }
479}
480
481#[cfg(test)]
482mod test_mul_assign {
483 use crate::integer::{MatZ, Z};
484 use std::str::FromStr;
485
486 #[test]
488 fn consistency() {
489 let mut a = MatZ::from_str("[[2, 1],[-1, 0]]").unwrap();
490 let b = i32::MAX;
491 let cmp = &a * b;
492
493 a *= b;
494
495 assert_eq!(cmp, a);
496 }
497
498 #[test]
500 fn availability() {
501 let mut a = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
502 let b = Z::from(2);
503
504 a *= &b;
505 a *= b;
506 a *= 1_u8;
507 a *= 1_u16;
508 a *= 1_u32;
509 a *= 1_u64;
510 a *= 1_i8;
511 a *= 1_i16;
512 a *= 1_i32;
513 a *= 1_i64;
514 }
515}