qfall_math/integer/mat_z/default.rs
1// Copyright © 2023 Marcel Luca Schmidt
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Initialize a [`MatZ`] with common defaults, e.g., zero and identity.
10
11use super::MatZ;
12use crate::utils::index::evaluate_indices;
13use flint_sys::fmpz_mat::{fmpz_mat_init, fmpz_mat_one};
14use std::{fmt::Display, mem::MaybeUninit};
15
16impl MatZ {
17 /// Creates a new matrix with `num_rows` rows, `num_cols` columns and
18 /// zeros as entries.
19 ///
20 /// Parameters:
21 /// - `num_rows`: number of rows the new matrix should have
22 /// - `num_cols`: number of columns the new matrix should have
23 ///
24 /// Returns a new [`MatZ`] instance of the provided dimensions.
25 ///
26 /// # Examples
27 /// ```
28 /// use qfall_math::integer::MatZ;
29 ///
30 /// let matrix = MatZ::new(5, 10);
31 /// ```
32 ///
33 /// # Panics ...
34 /// - if the number of rows or columns is negative, `0`, or does not fit into an [`i64`].
35 pub fn new(
36 num_rows: impl TryInto<i64> + Display,
37 num_cols: impl TryInto<i64> + Display,
38 ) -> Self {
39 let (num_rows_i64, num_cols_i64) = evaluate_indices(num_rows, num_cols).unwrap();
40
41 assert!(
42 num_rows_i64 != 0 && num_cols_i64 != 0,
43 "A matrix can not contain 0 rows or 0 columns"
44 );
45
46 let mut matrix = MaybeUninit::uninit();
47 unsafe {
48 fmpz_mat_init(matrix.as_mut_ptr(), num_rows_i64, num_cols_i64);
49
50 // Construct MatZ from previously initialized fmpz_mat
51 MatZ {
52 matrix: matrix.assume_init(),
53 }
54 }
55 }
56
57 /// Generate a `num_rows` times `num_columns` matrix with `1` on the
58 /// diagonal and `0` anywhere else.
59 ///
60 /// Parameters:
61 /// - `rum_rows`: the number of rows of the identity matrix
62 /// - `num_columns`: the number of columns of the identity matrix
63 ///
64 /// Returns a matrix with `1` across the diagonal and `0` anywhere else.
65 ///
66 /// # Examples
67 /// ```
68 /// use qfall_math::integer::MatZ;
69 ///
70 /// let matrix = MatZ::identity(2, 3);
71 ///
72 /// let identity = MatZ::identity(10, 10);
73 /// ```
74 ///
75 /// # Panics ...
76 /// - if the provided number of rows and columns are not suited to create a matrix.
77 /// For further information see [`MatZ::new`].
78 pub fn identity(
79 num_rows: impl TryInto<i64> + Display,
80 num_cols: impl TryInto<i64> + Display,
81 ) -> Self {
82 let mut out = MatZ::new(num_rows, num_cols);
83 unsafe { fmpz_mat_one(&mut out.matrix) };
84 out
85 }
86}
87
88#[cfg(test)]
89mod test_new {
90 use crate::{
91 integer::{MatZ, Z},
92 traits::MatrixGetEntry,
93 };
94
95 /// Ensure that entries of a new matrix are `0`.
96 #[test]
97 fn entry_zero() {
98 let matrix = MatZ::new(2, 2);
99
100 let entry_1 = matrix.get_entry(0, 0).unwrap();
101 let entry_2 = matrix.get_entry(0, 1).unwrap();
102 let entry_3 = matrix.get_entry(1, 0).unwrap();
103 let entry_4 = matrix.get_entry(1, 1).unwrap();
104
105 assert_eq!(Z::ZERO, entry_1);
106 assert_eq!(Z::ZERO, entry_2);
107 assert_eq!(Z::ZERO, entry_3);
108 assert_eq!(Z::ZERO, entry_4);
109 }
110
111 /// Ensure that a new zero matrix fails with `0` as `num_cols`.
112 #[should_panic]
113 #[test]
114 fn error_zero_num_cols() {
115 let _ = MatZ::new(1, 0);
116 }
117
118 /// Ensure that a new zero matrix fails with `0` as `num_rows`.
119 #[should_panic]
120 #[test]
121 fn error_zero_num_rows() {
122 let _ = MatZ::new(0, 1);
123 }
124}
125
126#[cfg(test)]
127mod test_identity {
128 use crate::{
129 integer::{MatZ, Z},
130 traits::MatrixGetEntry,
131 };
132
133 /// Tests if an identity matrix is set from a zero matrix.
134 #[test]
135 fn identity() {
136 let matrix = MatZ::identity(10, 10);
137
138 for i in 0..10 {
139 for j in 0..10 {
140 if i != j {
141 assert_eq!(Z::ZERO, matrix.get_entry(i, j).unwrap());
142 } else {
143 assert_eq!(Z::ONE, matrix.get_entry(i, j).unwrap());
144 }
145 }
146 }
147 }
148
149 /// Tests if function works for a non-square matrix
150 #[test]
151 fn non_square_works() {
152 let matrix = MatZ::identity(10, 7);
153
154 for i in 0..10 {
155 for j in 0..7 {
156 if i != j {
157 assert_eq!(Z::ZERO, matrix.get_entry(i, j).unwrap());
158 } else {
159 assert_eq!(Z::ONE, matrix.get_entry(i, j).unwrap());
160 }
161 }
162 }
163
164 let matrix = MatZ::identity(7, 10);
165
166 for i in 0..7 {
167 for j in 0..10 {
168 if i != j {
169 assert_eq!(Z::ZERO, matrix.get_entry(i, j).unwrap());
170 } else {
171 assert_eq!(Z::ONE, matrix.get_entry(i, j).unwrap());
172 }
173 }
174 }
175 }
176}