1use super::super::MatQ;
12use crate::integer::Z;
13use crate::macros::arithmetics::{
14 arithmetic_assign_between_types, arithmetic_assign_trait_borrowed_to_owned,
15 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
16 arithmetic_trait_reverse,
17};
18use crate::macros::for_others::implement_for_others;
19use crate::rational::Q;
20use crate::traits::MatrixDimensions;
21use flint_sys::fmpq_mat::{fmpq_mat_scalar_mul_fmpq, fmpq_mat_scalar_mul_fmpz};
22use std::ops::{Mul, MulAssign};
23
24impl Mul<&Z> for &MatQ {
25 type Output = MatQ;
26 fn mul(self, scalar: &Z) -> Self::Output {
46 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
47 unsafe {
48 fmpq_mat_scalar_mul_fmpz(&mut out.matrix, &self.matrix, &scalar.value);
49 }
50 out
51 }
52}
53
54arithmetic_trait_reverse!(Mul, mul, Q, MatQ, MatQ);
55
56arithmetic_trait_borrowed_to_owned!(Mul, mul, MatQ, Q, MatQ);
57arithmetic_trait_borrowed_to_owned!(Mul, mul, Q, MatQ, MatQ);
58arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatQ, Q, MatQ);
59arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Q, MatQ, MatQ);
60
61implement_for_others!(Z, MatQ, MatQ, Mul Scalar for i8 i16 i32 i64 u8 u16 u32 u64);
62
63impl Mul<&Q> for &MatQ {
64 type Output = MatQ;
65 fn mul(self, scalar: &Q) -> Self::Output {
85 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
86 unsafe {
87 fmpq_mat_scalar_mul_fmpq(&mut out.matrix, &self.matrix, &scalar.value);
88 }
89 out
90 }
91}
92
93arithmetic_trait_reverse!(Mul, mul, Z, MatQ, MatQ);
94
95arithmetic_trait_borrowed_to_owned!(Mul, mul, MatQ, Z, MatQ);
96arithmetic_trait_borrowed_to_owned!(Mul, mul, Z, MatQ, MatQ);
97arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatQ, Z, MatQ);
98arithmetic_trait_mixed_borrowed_owned!(Mul, mul, Z, MatQ, MatQ);
99
100implement_for_others!(Q, MatQ, MatQ, Mul Scalar for f32 f64);
101
102impl MulAssign<&Q> for MatQ {
103 fn mul_assign(&mut self, scalar: &Q) {
129 unsafe { fmpq_mat_scalar_mul_fmpq(&mut self.matrix, &self.matrix, &scalar.value) };
130 }
131}
132
133impl MulAssign<&Z> for MatQ {
134 fn mul_assign(&mut self, other: &Z) {
136 unsafe { fmpq_mat_scalar_mul_fmpz(&mut self.matrix, &self.matrix, &other.value) };
137 }
138}
139
140arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatQ, Q);
141arithmetic_assign_trait_borrowed_to_owned!(MulAssign, mul_assign, MatQ, Z);
142arithmetic_assign_between_types!(MulAssign, mul_assign, MatQ, Z, u64 u32 u16 u8 i64 i32 i16 i8);
143arithmetic_assign_between_types!(MulAssign, mul_assign, MatQ, Q, f32 f64);
144
145#[cfg(test)]
146mod test_mul_z {
147 use super::MatQ;
148 use crate::integer::Z;
149 use std::str::FromStr;
150
151 #[test]
153 fn borrowed_correctness() {
154 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
155 let mat_2 = mat_1.clone();
156 let mat_3 = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
157 let integer = Z::from(3);
158
159 let mat_1 = &mat_1 * &integer;
160 let mat_2 = &integer * &mat_2;
161
162 assert_eq!(mat_3, mat_1);
163 assert_eq!(mat_3, mat_2);
164 }
165
166 #[test]
168 fn owned_correctness() {
169 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
170 let mat_2 = mat_1.clone();
171 let mat_3 = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
172 let integer_1 = Z::from(3);
173 let integer_2 = Z::from(3);
174
175 let mat_1 = mat_1 * integer_1;
176 let mat_2 = integer_2 * mat_2;
177
178 assert_eq!(mat_3, mat_1);
179 assert_eq!(mat_3, mat_2);
180 }
181
182 #[test]
184 fn half_correctness() {
185 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
186 let mat_2 = mat_1.clone();
187 let mat_3 = mat_1.clone();
188 let mat_4 = mat_1.clone();
189 let mat_5 = MatQ::from_str("[[2, 3],[3/2, 6]]").unwrap();
190 let integer_1 = Z::from(3);
191 let integer_2 = Z::from(3);
192
193 let mat_1 = mat_1 * &integer_1;
194 let mat_2 = &integer_2 * mat_2;
195 let mat_3 = &mat_3 * integer_1;
196 let mat_4 = integer_2 * &mat_4;
197
198 assert_eq!(mat_5, mat_1);
199 assert_eq!(mat_5, mat_2);
200 assert_eq!(mat_5, mat_3);
201 assert_eq!(mat_5, mat_4);
202 }
203
204 #[test]
206 #[allow(clippy::erasing_op)]
207 fn different_types() {
208 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
209 let mat_2 = MatQ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
210 let mat_3 = MatQ::from_str("[[1],[0],[8]]").unwrap();
211 let mat_4 = MatQ::from_str("[[0],[0],[0]]").unwrap();
212 let mat_5 = MatQ::from_str("[[-1/2],[0],[-4]]").unwrap();
213 let mat_6 = MatQ::from_str("[[6, 15, 18],[3, 9, 3]]").unwrap();
214
215 assert_eq!(mat_3, 2u8 * &mat_1);
216 assert_eq!(mat_3, 2i8 * &mat_1);
217 assert_eq!(mat_3, 2u16 * &mat_1);
218 assert_eq!(mat_3, 2i16 * &mat_1);
219 assert_eq!(mat_3, 2u32 * &mat_1);
220 assert_eq!(mat_3, 2i32 * &mat_1);
221 assert_eq!(mat_3, 2u64 * &mat_1);
222 assert_eq!(mat_3, 2i64 * &mat_1);
223 assert_eq!(mat_4, 0 * &mat_1);
224 assert_eq!(mat_5, -1 * mat_1);
225 assert_eq!(mat_6, mat_2 * 3);
226 }
227
228 #[test]
230 fn different_dimensions_correctness() {
231 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
232 let mat_2 = MatQ::from_str("[[2, 5/8, 6],[1, 3, 1/7]]").unwrap();
233 let mat_3 = MatQ::from_str("[[3/2],[0],[12]]").unwrap();
234 let mat_4 = MatQ::from_str("[[6, 15/8, 18],[3, 9, 3/7]]").unwrap();
235 let integer = Z::from(3);
236
237 assert_eq!(mat_3, &integer * mat_1);
238 assert_eq!(mat_4, integer * mat_2);
239 }
240
241 #[test]
243 fn large_entries() {
244 let mat_1 = MatQ::from_str(&format!("[[1],[{}],[1/{}]]", i64::MAX, i64::MAX)).unwrap();
245 let mat_2 = MatQ::from_str("[[3]]").unwrap();
246 let mat_3 = MatQ::from_str(&format!(
247 "[[3],[{}],[3/{}]]",
248 3 * i64::MAX as i128,
249 i64::MAX
250 ))
251 .unwrap();
252 let mat_4 = MatQ::from_str(&format!("[[{}]]", 3 * i64::MAX as i128)).unwrap();
253 let integer_1 = Z::from(3);
254 let integer_2 = Z::from(i64::MAX);
255
256 assert_eq!(mat_3, integer_1 * mat_1);
257 assert_eq!(mat_4, integer_2 * mat_2);
258 }
259}
260
261#[cfg(test)]
262mod test_mul_q {
263 use super::MatQ;
264 use crate::rational::Q;
265 use std::str::FromStr;
266
267 #[test]
269 fn borrowed_correctness() {
270 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
271 let mat_2 = mat_1.clone();
272 let mat_3 = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
273 let rational = Q::from((3, 2));
274
275 let mat_1 = &mat_1 * &rational;
276 let mat_2 = &mat_2 * &rational;
277
278 assert_eq!(mat_3, mat_1);
279 assert_eq!(mat_3, mat_2);
280 }
281
282 #[test]
284 fn owned_correctness() {
285 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
286 let mat_2 = mat_1.clone();
287 let mat_3 = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
288 let rational_1 = Q::from((3, 2));
289 let rational_2 = Q::from((3, 2));
290
291 let mat_1 = mat_1 * rational_1;
292 let mat_2 = rational_2 * mat_2;
293
294 assert_eq!(mat_3, mat_1);
295 assert_eq!(mat_3, mat_2);
296 }
297
298 #[test]
300 fn half_correctness() {
301 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
302 let mat_2 = mat_1.clone();
303 let mat_3 = mat_1.clone();
304 let mat_4 = mat_1.clone();
305 let mat_5 = MatQ::from_str("[[1, 3/2],[3/4, 3]]").unwrap();
306 let rational_1 = Q::from((3, 2));
307 let rational_2 = Q::from((3, 2));
308
309 let mat_1 = mat_1 * &rational_1;
310 let mat_2 = &rational_2 * mat_2;
311 let mat_3 = &mat_3 * rational_1;
312 let mat_4 = rational_2 * &mat_4;
313
314 assert_eq!(mat_5, mat_1);
315 assert_eq!(mat_5, mat_2);
316 assert_eq!(mat_5, mat_3);
317 assert_eq!(mat_5, mat_4);
318 }
319
320 #[test]
322 #[allow(clippy::erasing_op)]
323 fn different_types() {
324 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
325 let mat_2 = MatQ::from_str("[[2, 5, 6],[1, 3, 1]]").unwrap();
326 let mat_3 = MatQ::from_str("[[5/4],[0],[10]]").unwrap();
327 let mat_4 = MatQ::from_str("[[-799/8],[0],[-799]]").unwrap();
328 let mat_5 = MatQ::from_str("[[285/4, 1425/8, 855/4],[285/8, 855/8, 285/8]]").unwrap();
329
330 assert_eq!(mat_3, 2.5f32 * &mat_1);
331 assert_eq!(mat_4, -199.75f64 * mat_1);
332 assert_eq!(mat_5, mat_2 * 35.625);
333 }
334
335 #[test]
337 fn different_dimensions_correctness() {
338 let mat_1 = MatQ::from_str("[[1/2],[0],[4]]").unwrap();
339 let mat_2 = MatQ::from_str("[[2, 5/8, 6],[1, 3, 1/7]]").unwrap();
340 let mat_3 = MatQ::from_str("[[3/4],[0],[6]]").unwrap();
341 let mat_4 = MatQ::from_str("[[3, 15/16, 9],[3/2, 9/2, 3/14]]").unwrap();
342 let rational = Q::from((3, 2));
343
344 assert_eq!(mat_3, &rational * mat_1);
345 assert_eq!(mat_4, rational * mat_2);
346 }
347
348 #[test]
350 fn large_entries() {
351 let mat_1 = MatQ::from_str(&format!("[[1],[{}],[1/{}]]", i64::MAX, i64::MAX)).unwrap();
352 let mat_2 = MatQ::from_str("[[3]]").unwrap();
353 let mat_3 = MatQ::from_str(&format!(
354 "[[3/2],[{}/2],[3/{}]]",
355 3 * i64::MAX as i128,
356 2 * i64::MAX as i128
357 ))
358 .unwrap();
359 let mat_4 = MatQ::from_str(&format!("[[{}/2]]", 3 * i64::MAX as i128)).unwrap();
360 let mat_5 = MatQ::from_str(&format!("[[6/{}]]", i64::MAX)).unwrap();
361 let rational_1 = Q::from((3, 2));
362 let rational_2 = Q::from((i64::MAX, 2));
363 let rational_3 = Q::from((2, i64::MAX));
364
365 assert_eq!(mat_3, rational_1 * mat_1);
366 assert_eq!(mat_4, rational_2 * &mat_2);
367 assert_eq!(mat_5, rational_3 * mat_2);
368 }
369}
370
371#[cfg(test)]
372mod test_mul_assign {
373 use crate::integer::Z;
374 use crate::rational::{MatQ, Q};
375 use std::str::FromStr;
376
377 #[test]
379 fn consistency() {
380 let mut a = MatQ::from_str("[[2, 1],[-1, 0]]").unwrap();
381 let b = Q::from((1, i32::MAX));
382 let cmp = &a * &b;
383
384 a *= b;
385
386 assert_eq!(cmp, a);
387 }
388
389 #[test]
391 fn availability() {
392 let mut a = MatQ::from_str("[[2, 1],[1, 2]]").unwrap();
393 let b = Z::from(2);
394 let c = Q::from((2, 3));
395
396 a *= &b;
397 a *= b;
398 a *= &c;
399 a *= c;
400 a *= 1_u8;
401 a *= 1_u16;
402 a *= 1_u32;
403 a *= 1_u64;
404 a *= 1_i8;
405 a *= 1_i16;
406 a *= 1_i32;
407 a *= 1_i64;
408 a *= 1.0_f32;
409 a *= 1.0_f64;
410 }
411}