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