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 flint3_sys::{
23 fmpz, 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
51 let scalar_ptr = &scalar.value as *const fmpz as *mut fmpz;
52
53 unsafe {
54 fmpz_mod_mat_scalar_mul_fmpz(
55 &mut out.matrix,
56 &self.matrix,
57 scalar_ptr,
58 self.modulus.get_fmpz_mod_ctx_struct(),
59 );
60 }
61 out
62 }
63}
64
65arithmetic_trait_reverse!(Mul, mul, Z, MatZq, MatZq);
66
67arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZq, Z, MatZq);
68arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatZq, MatZq);
69arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZq, Z, MatZq);
70arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatZq, MatZq);
71
72implement_for_others!(Z, MatZq, MatZq, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
73
74impl Mul<&Zq> for &MatZq {
75 type Output = MatZq;
76 fn mul(self, scalar: &Zq) -> Self::Output {
98 self.mul_scalar_safe(scalar).unwrap()
99 }
100}
101
102arithmetic_trait_reverse!(Mul, mul, Zq, MatZq, MatZq);
103
104arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZq, Zq, MatZq);
105arithmetic_trait_borrowed_to_owned!(Mul, mul, Zq, MatZq, MatZq);
106arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZq, Zq, MatZq);
107arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Zq, MatZq, MatZq);
108
109impl MatZq {
110 pub fn mul_scalar_safe(&self, scalar: &Zq) -> Result<Self, MathError> {
133 if !self.compare_base(scalar) {
134 return Err(self.call_compare_base_error(scalar).unwrap());
135 }
136
137 let scalar_ptr = &scalar.value.value as *const fmpz as *mut fmpz;
138
139 let mut out = MatZq::new(self.get_num_rows(), self.get_num_columns(), self.get_mod());
140 unsafe {
141 fmpz_mod_mat_scalar_mul_fmpz(
142 &mut out.matrix,
143 &self.matrix,
144 scalar_ptr,
145 self.modulus.get_fmpz_mod_ctx_struct(),
146 );
147 }
148 Ok(out)
149 }
150}
151
152impl MulAssign<&Z> for MatZq {
153 fn mul_assign(&mut self, scalar: &Z) {
179 let scalar_ptr = &scalar.value as *const fmpz as *mut fmpz;
180
181 unsafe {
182 fmpz_mod_mat_scalar_mul_fmpz(
183 &mut self.matrix,
184 &self.matrix,
185 scalar_ptr,
186 self.modulus.get_fmpz_mod_ctx_struct(),
187 )
188 };
189 }
190}
191
192impl MulAssign<&Zq> for MatZq {
193 fn mul_assign(&mut self, scalar: &Zq) {
198 if !self.compare_base(scalar) {
199 panic!("{}", self.call_compare_base_error(scalar).unwrap())
200 }
201
202 let scalar_ptr = &scalar.value.value as *const fmpz as *mut fmpz;
203
204 unsafe {
205 fmpz_mod_mat_scalar_mul_fmpz(
206 &mut self.matrix,
207 &self.matrix,
208 scalar_ptr,
209 self.modulus.get_fmpz_mod_ctx_struct(),
210 )
211 };
212 }
213}
214
215arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatZq, Zq);
216
217impl MulAssign<i64> for MatZq {
218 fn mul_assign(&mut self, other: i64) {
220 unsafe {
221 fmpz_mod_mat_scalar_mul_si(
222 &mut self.matrix,
223 &self.matrix,
224 other,
225 self.modulus.get_fmpz_mod_ctx_struct(),
226 )
227 };
228 }
229}
230
231impl MulAssign<u64> for MatZq {
232 fn mul_assign(&mut self, other: u64) {
234 unsafe {
235 fmpz_mod_mat_scalar_mul_ui(
236 &mut self.matrix,
237 &self.matrix,
238 other,
239 self.modulus.get_fmpz_mod_ctx_struct(),
240 )
241 };
242 }
243}
244
245arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatZq, Z);
246arithmetic_assign_between_types!(MulAssign, mul_assign, MatZq, i64, i32 i16 i8);
247arithmetic_assign_between_types!(MulAssign, mul_assign, MatZq, u64, u32 u16 u8);
248
249#[cfg(test)]
250mod test_mul_z {
251 use crate::integer::Z;
252 use crate::integer_mod_q::MatZq;
253 use std::str::FromStr;
254
255 #[test]
257 fn borrowed_correctness() {
258 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
259 let mat_2 = mat_1.clone();
260 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
261 let integer = Z::from(2);
262
263 let mat_1 = &mat_1 * &integer;
264 let mat_2 = &integer * &mat_2;
265
266 assert_eq!(mat_3, mat_1);
267 assert_eq!(mat_3, mat_2);
268 }
269
270 #[test]
272 fn owned_correctness() {
273 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
274 let mat_2 = mat_1.clone();
275 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
276 let integer_1 = Z::from(2);
277 let integer_2 = Z::from(2);
278
279 let mat_1 = mat_1 * integer_1;
280 let mat_2 = integer_2 * mat_2;
281
282 assert_eq!(mat_3, mat_1);
283 assert_eq!(mat_3, mat_2);
284 }
285
286 #[test]
288 fn half_correctness() {
289 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
290 let mat_2 = mat_1.clone();
291 let mat_3 = mat_1.clone();
292 let mat_4 = mat_1.clone();
293 let mat_5 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
294 let integer_1 = Z::from(2);
295 let integer_2 = Z::from(2);
296
297 let mat_1 = mat_1 * &integer_1;
298 let mat_2 = &integer_2 * mat_2;
299 let mat_3 = &mat_3 * integer_1;
300 let mat_4 = integer_2 * &mat_4;
301
302 assert_eq!(mat_5, mat_1);
303 assert_eq!(mat_5, mat_2);
304 assert_eq!(mat_5, mat_3);
305 assert_eq!(mat_5, mat_4);
306 }
307
308 #[test]
310 #[allow(clippy::erasing_op)]
311 fn different_types() {
312 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
313 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
314 let mat_3 = MatZq::from_str("[[23],[0],[4]] mod 61").unwrap();
315 let mat_4 = MatZq::from_str("[[0],[0],[0]] mod 61").unwrap();
316 let mat_5 = MatZq::from_str("[[-42],[0],[-2]] mod 61").unwrap();
317 let mat_6 = MatZq::from_str("[[6, 18, 15],[12, 126, 9]] mod 61").unwrap();
318
319 assert_eq!(mat_3, 2u8 * &mat_1);
320 assert_eq!(mat_3, 2i8 * &mat_1);
321 assert_eq!(mat_3, 2u16 * &mat_1);
322 assert_eq!(mat_3, 2i16 * &mat_1);
323 assert_eq!(mat_3, 2u32 * &mat_1);
324 assert_eq!(mat_3, 2i32 * &mat_1);
325 assert_eq!(mat_3, 2u64 * &mat_1);
326 assert_eq!(mat_3, 2i64 * &mat_1);
327 assert_eq!(mat_4, 0 * &mat_1);
328 assert_eq!(mat_5, -1 * mat_1);
329 assert_eq!(mat_6, mat_2 * 3);
330 }
331
332 #[test]
334 fn different_dimensions_correctness() {
335 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
336 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
337 let mat_3 = MatZq::from_str("[[84],[0],[4]] mod 61").unwrap();
338 let mat_4 = MatZq::from_str("[[4, 12, 10],[8, 84, 6]] mod 61").unwrap();
339 let integer = Z::from(2);
340
341 assert_eq!(mat_3, &integer * mat_1);
342 assert_eq!(mat_4, integer * mat_2);
343 }
344
345 #[test]
347 fn large_entries() {
348 let mat_1 = MatZq::from_str(&format!("[[1],[{}],[4]] mod {}", i64::MAX, u64::MAX)).unwrap();
349 let mat_2 = MatZq::from_str(&format!("[[3]] mod {}", u64::MAX)).unwrap();
350 let mat_3 =
351 MatZq::from_str(&format!("[[3],[{}],[12]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
352 let mat_4 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
353 let integer_1 = Z::from(3);
354 let integer_2 = Z::from(i64::MAX);
355
356 assert_eq!(mat_3, integer_1 * mat_1);
357 assert_eq!(mat_4, integer_2 * mat_2);
358 }
359}
360
361#[cfg(test)]
362mod test_mul_zq {
363 use crate::integer_mod_q::{MatZq, Zq};
364 use std::str::FromStr;
365
366 #[test]
368 fn borrowed_correctness() {
369 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
370 let mat_2 = mat_1.clone();
371 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
372 let integer = Zq::from((2, 61));
373
374 let mat_1 = &mat_1 * &integer;
375 let mat_2 = &integer * &mat_2;
376
377 assert_eq!(mat_3, mat_1);
378 assert_eq!(mat_3, mat_2);
379 }
380
381 #[test]
383 fn owned_correctness() {
384 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
385 let mat_2 = mat_1.clone();
386 let mat_3 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
387 let integer_1 = Zq::from((2, 61));
388 let integer_2 = Zq::from((2, 61));
389
390 let mat_1 = mat_1 * integer_1;
391 let mat_2 = integer_2 * mat_2;
392
393 assert_eq!(mat_3, mat_1);
394 assert_eq!(mat_3, mat_2);
395 }
396
397 #[test]
399 fn half_correctness() {
400 let mat_1 = MatZq::from_str("[[42, 17],[8, 6]] mod 61").unwrap();
401 let mat_2 = mat_1.clone();
402 let mat_3 = mat_1.clone();
403 let mat_4 = mat_1.clone();
404 let mat_5 = MatZq::from_str("[[84, 34],[16, 12]] mod 61").unwrap();
405 let integer_1 = Zq::from((2, 61));
406 let integer_2 = Zq::from((2, 61));
407
408 let mat_1 = mat_1 * &integer_1;
409 let mat_2 = &integer_2 * mat_2;
410 let mat_3 = &mat_3 * integer_1;
411 let mat_4 = integer_2 * &mat_4;
412
413 assert_eq!(mat_5, mat_1);
414 assert_eq!(mat_5, mat_2);
415 assert_eq!(mat_5, mat_3);
416 assert_eq!(mat_5, mat_4);
417 }
418
419 #[test]
421 fn different_dimensions_correctness() {
422 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
423 let mat_2 = MatZq::from_str("[[2, 6, 5],[4, 42, 3]] mod 61").unwrap();
424 let mat_3 = MatZq::from_str("[[84],[0],[4]] mod 61").unwrap();
425 let mat_4 = MatZq::from_str("[[4, 12, 10],[8, 84, 6]] mod 61").unwrap();
426 let integer = Zq::from((2, 61));
427
428 assert_eq!(mat_3, &integer * mat_1);
429 assert_eq!(mat_4, integer * mat_2);
430 }
431
432 #[test]
434 fn large_entries() {
435 let mat_1 = MatZq::from_str(&format!("[[1],[{}],[4]] mod {}", i64::MAX, u64::MAX)).unwrap();
436 let mat_2 = MatZq::from_str(&format!("[[3]] mod {}", u64::MAX)).unwrap();
437 let mat_3 =
438 MatZq::from_str(&format!("[[3],[{}],[12]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
439 let mat_4 = MatZq::from_str(&format!("[[{}]] mod {}", i64::MAX - 1, u64::MAX)).unwrap();
440 let integer_1 = Zq::from((3, u64::MAX));
441 let integer_2 = Zq::from((i64::MAX, u64::MAX));
442
443 assert_eq!(mat_3, integer_1 * mat_1);
444 assert_eq!(mat_4, integer_2 * mat_2);
445 }
446
447 #[test]
449 #[should_panic]
450 fn different_moduli_error() {
451 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
452 let integer = Zq::from((2, 3));
453
454 _ = &integer * mat_1;
455 }
456
457 #[test]
459 fn different_moduli_error_safe() {
460 let mat_1 = MatZq::from_str("[[42],[0],[2]] mod 61").unwrap();
461 let integer = Zq::from((2, 3));
462
463 let mat_2 = &mat_1.mul_scalar_safe(&integer);
464
465 assert!(mat_2.is_err());
466 }
467}
468
469#[cfg(test)]
470mod test_mul_assign {
471 use crate::integer::Z;
472 use crate::integer_mod_q::{MatZq, Zq};
473 use std::str::FromStr;
474
475 #[test]
477 fn consistency() {
478 let mut a = MatZq::from_str(&format!("[[2, 1],[-1, 0]] mod {}", u64::MAX - 1)).unwrap();
479 let b = i32::MAX;
480 let cmp = &a * b;
481
482 a *= b;
483
484 assert_eq!(cmp, a);
485 }
486
487 #[test]
489 fn availability() {
490 let mut mat_zq = MatZq::from_str("[[2, 1],[1, 2]] mod 7").unwrap();
491 let z = Z::from(2);
492 let zq = Zq::from((2, 7));
493
494 mat_zq *= &z;
495 mat_zq *= z;
496 mat_zq *= &zq;
497 mat_zq *= zq;
498 mat_zq *= 1_u8;
499 mat_zq *= 1_u16;
500 mat_zq *= 1_u32;
501 mat_zq *= 1_u64;
502 mat_zq *= 1_i8;
503 mat_zq *= 1_i16;
504 mat_zq *= 1_i32;
505 mat_zq *= 1_i64;
506 }
507
508 #[test]
510 #[should_panic]
511 fn mismatching_modulus_zq() {
512 let mut mat_zq = MatZq::from_str("[[2, 1],[1, 2]] mod 7").unwrap();
513
514 let zq = Zq::from((2, u64::MAX - 1));
515
516 mat_zq *= &zq;
517 }
518}