qfall_math/integer_mod_q/mat_zq/
concat.rs1use super::MatZq;
12use crate::{
13 error::MathError,
14 traits::{CompareBase, Concatenate, MatrixDimensions},
15};
16use flint3_sys::{fmpz_mod_mat_concat_horizontal, fmpz_mod_mat_concat_vertical};
17
18impl Concatenate for &MatZq {
19 type Output = MatZq;
20
21 fn concat_vertical(self, other: Self) -> Result<Self::Output, crate::error::MathError> {
48 if self.get_num_columns() != other.get_num_columns() {
49 return Err(MathError::MismatchingMatrixDimension(format!(
50 "Tried to concatenate vertically a '{}x{}' matrix and a '{}x{}' matrix.",
51 self.get_num_rows(),
52 self.get_num_columns(),
53 other.get_num_rows(),
54 other.get_num_columns()
55 )));
56 }
57
58 if !self.compare_base(other) {
59 return Err(self.call_compare_base_error(other).unwrap());
60 }
61
62 let mut out = MatZq::new(
63 self.get_num_rows() + other.get_num_rows(),
64 self.get_num_columns(),
65 self.get_mod(),
66 );
67 unsafe {
68 fmpz_mod_mat_concat_vertical(
69 &mut out.matrix,
70 &self.matrix,
71 &other.matrix,
72 self.modulus.get_fmpz_mod_ctx_struct(),
73 );
74 }
75 Ok(out)
76 }
77
78 fn concat_horizontal(self, other: Self) -> Result<Self::Output, crate::error::MathError> {
105 if self.get_num_rows() != other.get_num_rows() {
106 return Err(MathError::MismatchingMatrixDimension(format!(
107 "Tried to concatenate horizontally a '{}x{}' matrix and a '{}x{}' matrix.",
108 self.get_num_rows(),
109 self.get_num_columns(),
110 other.get_num_rows(),
111 other.get_num_columns()
112 )));
113 }
114
115 if !self.compare_base(other) {
116 return Err(self.call_compare_base_error(other).unwrap());
117 }
118
119 let mut out = MatZq::new(
120 self.get_num_rows(),
121 self.get_num_columns() + other.get_num_columns(),
122 self.get_mod(),
123 );
124 unsafe {
125 fmpz_mod_mat_concat_horizontal(
126 &mut out.matrix,
127 &self.matrix,
128 &other.matrix,
129 self.modulus.get_fmpz_mod_ctx_struct(),
130 );
131 }
132
133 Ok(out)
134 }
135}
136
137#[cfg(test)]
138mod test_concatenate {
139 use crate::{
140 integer_mod_q::MatZq,
141 traits::{Concatenate, MatrixDimensions},
142 };
143 use std::str::FromStr;
144
145 #[test]
148 fn dimensions_vertical() {
149 let mat_1 = MatZq::new(13, 5, 17);
150 let mat_2 = MatZq::new(17, 5, 17);
151 let mat_3 = MatZq::new(17, 6, 17);
152
153 let mat_vert = mat_1.concat_vertical(&mat_2).unwrap();
154
155 assert_eq!(5, mat_vert.get_num_columns());
156 assert_eq!(30, mat_vert.get_num_rows());
157 assert!(mat_1.concat_vertical(&mat_3).is_err());
158 }
159
160 #[test]
163 fn dimensions_horizontal() {
164 let mat_1 = MatZq::new(13, 5, 17);
165 let mat_2 = MatZq::new(17, 5, 17);
166 let mat_3 = MatZq::new(17, 6, 17);
167
168 let mat_hor = mat_2.concat_horizontal(&mat_3).unwrap();
169
170 assert_eq!(11, mat_hor.get_num_columns());
171 assert_eq!(17, mat_hor.get_num_rows());
172 assert!(mat_1.concat_horizontal(&mat_2).is_err());
173 }
174
175 #[test]
178 fn mismatching_moduli() {
179 let mat_1 = MatZq::new(2, 2, 17);
180 let mat_2 = MatZq::new(2, 2, 19);
181
182 let mat_hor = mat_1.concat_horizontal(&mat_2);
183 let mat_vert = mat_1.concat_vertical(&mat_2);
184
185 assert!(mat_hor.is_err());
186 assert!(mat_vert.is_err());
187 }
188
189 #[test]
191 fn vertically_correct() {
192 let mat_1 = MatZq::from_str(&format!(
193 "[[1, 2, {}],[4, 5, {}]] mod {}",
194 i64::MIN,
195 i64::MAX,
196 u64::MAX
197 ))
198 .unwrap();
199 let mat_2 = MatZq::from_str(&format!("[[-1, 2, -17]] mod {}", u64::MAX)).unwrap();
200
201 let mat_vertical = mat_1.concat_vertical(&mat_2).unwrap();
202
203 let cmp_mat = MatZq::from_str(&format!(
204 "[[1, 2, {}],[4, 5, {}],[-1, 2, -17]] mod {}",
205 i64::MIN,
206 i64::MAX,
207 u64::MAX,
208 ))
209 .unwrap();
210 assert_eq!(cmp_mat, mat_vertical);
211 }
212
213 #[test]
215 fn horizontally_correct() {
216 let mat_1 = MatZq::from_str(&format!(
217 "[[1, 2, {}],[4, 5, {}]] mod {}",
218 i64::MIN,
219 i64::MAX,
220 u64::MAX
221 ))
222 .unwrap();
223 let mat_2 = MatZq::from_str(&format!("[[-1, 2],[4, 5]] mod {}", u64::MAX)).unwrap();
224
225 let mat_horizontal = mat_1.concat_horizontal(&mat_2).unwrap();
226
227 let cmp_mat = MatZq::from_str(&format!(
228 "[[1, 2, {}, -1, 2],[4, 5, {}, 4, 5]] mod {}",
229 i64::MIN,
230 i64::MAX,
231 u64::MAX
232 ))
233 .unwrap();
234 assert_eq!(cmp_mat, mat_horizontal);
235 }
236}