1use super::super::MatZ;
12use crate::error::MathError;
13use crate::integer_mod_q::MatZq;
14use crate::macros::arithmetics::{
15 arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
16};
17use crate::rational::MatQ;
18use crate::traits::MatrixDimensions;
19use flint_sys::fmpq_mat::fmpq_mat_mul_r_fmpz_mat;
20use flint_sys::fmpz_mat::fmpz_mat_mul;
21use flint_sys::fmpz_mod_mat::_fmpz_mod_mat_reduce;
22use std::ops::Mul;
23
24impl Mul for &MatZ {
25 type Output = MatZ;
26
27 fn mul(self, other: Self) -> Self::Output {
52 self.mul_safe(other).unwrap()
53 }
54}
55
56arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, MatZ, MatZ);
57arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, MatZ, MatZ);
58
59impl Mul<&MatZq> for &MatZ {
60 type Output = MatZq;
61
62 fn mul(self, other: &MatZq) -> Self::Output {
88 assert_eq!(
89 self.get_num_columns(),
90 other.get_num_rows(),
91 "Tried to multiply matrices with mismatching matrix dimensions."
92 );
93
94 let mut new = MatZq::new(
95 self.get_num_rows(),
96 other.get_num_columns(),
97 other.get_mod(),
98 );
99 unsafe {
100 fmpz_mat_mul(&mut new.matrix.mat[0], &self.matrix, &other.matrix.mat[0]);
101 _fmpz_mod_mat_reduce(&mut new.matrix)
102 }
103 new
104 }
105}
106
107arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, MatZq, MatZq);
108arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, MatZq, MatZq);
109
110impl Mul<&MatQ> for &MatZ {
111 type Output = MatQ;
112
113 fn mul(self, other: &MatQ) -> Self::Output {
140 assert_eq!(
141 self.get_num_columns(),
142 other.get_num_rows(),
143 "Tried to multiply matrices with mismatching matrix dimensions."
144 );
145
146 let mut new = MatQ::new(self.get_num_rows(), other.get_num_columns());
147 unsafe { fmpq_mat_mul_r_fmpz_mat(&mut new.matrix, &self.matrix, &other.matrix) };
148 new
149 }
150}
151
152arithmetic_trait_borrowed_to_owned!(Mul, mul, MatZ, MatQ, MatQ);
153arithmetic_trait_mixed_borrowed_owned!(Mul, mul, MatZ, MatQ, MatQ);
154
155impl MatZ {
156 pub fn mul_safe(&self, other: &Self) -> Result<Self, MathError> {
180 if self.get_num_columns() != other.get_num_rows() {
181 return Err(MathError::MismatchingMatrixDimension(format!(
182 "Tried to multiply a '{}x{}' matrix and a '{}x{}' matrix.",
183 self.get_num_rows(),
184 self.get_num_columns(),
185 other.get_num_rows(),
186 other.get_num_columns()
187 )));
188 }
189
190 let mut new = MatZ::new(self.get_num_rows(), other.get_num_columns());
191 unsafe { fmpz_mat_mul(&mut new.matrix, &self.matrix, &other.matrix) };
192 Ok(new)
193 }
194}
195
196#[cfg(test)]
197mod test_mul {
198 use super::MatZ;
199 use crate::{integer::Z, traits::MatrixSetEntry};
200 use std::str::FromStr;
201
202 #[test]
204 fn square_correctness() {
205 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
206 let mat_2 = MatZ::identity(2, 2);
207 let mat_3 = MatZ::from_str("[[1, 2],[2, 1]]").unwrap();
208 let cmp = MatZ::from_str("[[4, 5],[5, 4]]").unwrap();
209
210 assert_eq!(mat_1, &mat_1 * &mat_2);
211 assert_eq!(cmp, &mat_1 * &mat_3);
212 }
213
214 #[test]
216 fn different_dimensions_correctness() {
217 let mat = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
218 let vec = MatZ::from_str("[[1],[0]]").unwrap();
219 let cmp = MatZ::from_str("[[2],[1]]").unwrap();
220
221 assert_eq!(cmp, &mat * &vec);
222 }
223
224 #[test]
226 fn large_entries() {
227 let mat = MatZ::from_str(&format!("[[{}, 1],[0, 2]]", i64::MAX)).unwrap();
228 let vec = MatZ::from_str(&format!("[[{}],[0]]", i64::MAX)).unwrap();
229 let mut cmp = MatZ::new(2, 1);
230 let max: Z = i64::MAX.into();
231 cmp.set_entry(0, 0, &(&max * &max)).unwrap();
232
233 assert_eq!(cmp, mat * vec);
234 }
235
236 #[test]
239 fn incompatible_dimensions() {
240 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
241 let mat_2 = MatZ::from_str("[[1, 0],[0, 1],[0, 0]]").unwrap();
242
243 assert!((mat_1.mul_safe(&mat_2)).is_err());
244 }
245}
246
247#[cfg(test)]
248mod test_mul_matzq {
249 use super::MatZq;
250 use crate::integer::MatZ;
251 use crate::{integer::Z, traits::MatrixSetEntry};
252 use std::str::FromStr;
253
254 #[test]
256 fn square_correctness() {
257 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
258 let mat_2 = MatZq::identity(2, 2, 3);
259 let mat_3 = MatZq::from_str("[[1, 2],[2, 1]] mod 3").unwrap();
260 let cmp = MatZq::from_str("[[4, 5],[2, 4]] mod 3").unwrap();
261
262 assert_eq!(MatZq::from((&mat_1, 3)), &mat_1 * &mat_2);
263 assert_eq!(cmp, &mat_1 * &mat_3);
264 }
265
266 #[test]
268 fn different_dimensions_correctness() {
269 let mat = MatZq::from_str("[[2, 1],[1, 2]] mod 3").unwrap();
270 let vec = MatZ::from_str("[[2, 0]]").unwrap();
271 let cmp = MatZq::from_str("[[4, 2]] mod 3").unwrap();
272
273 assert_eq!(cmp, &vec * &mat);
274 }
275
276 #[test]
278 fn large_entries() {
279 let mat =
280 MatZq::from_str(&format!("[[{}, 0],[1, 2]] mod {}", u64::MAX, u64::MAX - 58)).unwrap();
281 let vec = MatZ::from_str(&format!("[[{}, 0]]", u64::MAX)).unwrap();
282 let mut cmp = MatZq::new(1, 2, u64::MAX - 58);
283 let max: Z = u64::MAX.into();
284 cmp.set_entry(0, 0, &(&max * &max)).unwrap();
285
286 assert_eq!(cmp, vec * mat);
287 }
288
289 #[test]
292 #[should_panic]
293 fn errors() {
294 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
295 let mat_2 = MatZq::from_str("[[1, 0],[0, 1],[0, 0]] mod 4").unwrap();
296 let _ = &mat_1 * &mat_2;
297 }
298}
299
300#[cfg(test)]
301mod test_mul_matq {
302 use super::MatQ;
303 use crate::integer::MatZ;
304 use crate::rational::Q;
305 use crate::traits::MatrixSetEntry;
306 use std::str::FromStr;
307
308 #[test]
310 fn square_correctness() {
311 let mat_1 = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
312 let mat_2 = MatZ::identity(2, 2);
313 let mat_3 = MatZ::from_str("[[1, 2],[2, 1]]").unwrap();
314 let cmp = MatQ::from_str("[[5/3, 5],[11/6, 4]]").unwrap();
315
316 assert_eq!(mat_1, &mat_2 * &mat_1);
317 assert_eq!(cmp, &mat_3 * &mat_1);
318 }
319
320 #[test]
322 fn different_dimensions_correctness() {
323 let mat = MatQ::from_str("[[2/3, 1],[1/2, 2]]").unwrap();
324 let vec = MatZ::from_str("[[2, 0]]").unwrap();
325 let cmp = MatQ::from_str("[[4/3, 2]]").unwrap();
326
327 assert_eq!(cmp, &vec * &mat);
328 }
329
330 #[test]
332 fn large_entries() {
333 let mat = MatQ::from_str(&format!("[[{}, 0],[1, 2/{}]]", u64::MAX, u64::MAX)).unwrap();
334 let vec = MatZ::from_str(&format!("[[{}, 0]]", u64::MAX)).unwrap();
335 let mut cmp = MatQ::new(1, 2);
336 let max: Q = u64::MAX.into();
337 cmp.set_entry(0, 0, &(&max * &max)).unwrap();
338
339 assert_eq!(cmp, vec * mat);
340 }
341
342 #[test]
345 #[should_panic]
346 fn errors() {
347 let mat_1 = MatZ::from_str("[[2, 1],[1, 2]]").unwrap();
348 let mat_2 = MatQ::from_str("[[2/3, 0],[0, 1/2],[0, 0]]").unwrap();
349 let _ = &mat_1 * &mat_2;
350 }
351}