qfall_math/rational/mat_q/
gso.rs1use super::MatQ;
12use crate::traits::MatrixDimensions;
13use flint_sys::fmpq_mat::fmpq_mat_gso;
14
15impl MatQ {
16 pub fn gso(&self) -> Self {
27 let mut out = MatQ::new(self.get_num_rows(), self.get_num_columns());
28 unsafe {
29 fmpq_mat_gso(&mut out.matrix, &self.matrix);
30 }
31 out
32 }
33}
34
35#[cfg(test)]
36mod test_gso {
37 use crate::{
38 rational::{MatQ, Q},
39 traits::{MatrixGetEntry, MatrixGetSubmatrix},
40 };
41 use std::str::FromStr;
42
43 #[test]
45 fn gso_works() {
46 let mat = MatQ::from_str(
47 "[[-1, 2/7, 3/9, 4, 5/2],[-123/1000, 235/5, 123, 643/7172721, 123],[124/8981, 212, 452/2140, 12/5, 1],[0, 0, 0, 1, 1],[1, 2, 3, 4/3, 1]]",
48 )
49 .unwrap();
50
51 let mat_gso = mat.gso();
52
53 let cmp = Q::ZERO;
54 for i in 0..5 {
55 let vec_i = mat_gso.get_column(i).unwrap();
56 assert_ne!(cmp, vec_i.dot_product(&vec_i).unwrap());
57 for j in i + 1..5 {
58 let vec_j = mat_gso.get_column(j).unwrap();
59 assert_eq!(cmp, vec_i.dot_product(&vec_j).unwrap());
60 }
61 }
62 }
63
64 #[test]
66 fn gso_correct_values() {
67 let mat = MatQ::from_str("[[1, -1, 1],[1, 0, 1],[1, 1, 2]]").unwrap();
68
69 let mat_gso = mat.gso();
70
71 assert_eq!(
72 MatQ::from_str("[[1, -1, 1/6],[1, 0, -1/3],[1, 1, 1/6]]").unwrap(),
73 mat_gso
74 );
75 }
76
77 #[test]
79 fn gso_dependent_columns() {
80 let mat = MatQ::from_str("[[1, 2, 3, 4, 4],[1, 2, 3, 4, 5]]").unwrap();
81
82 let mat_gso = mat.gso();
83
84 let cmp = Q::ZERO;
85 for i in 0..5 {
86 let vec_i = mat_gso.get_column(i).unwrap();
87 for j in i + 1..5 {
88 let vec_j = mat_gso.get_column(j).unwrap();
89 assert_eq!(cmp, vec_i.dot_product(&vec_j).unwrap());
90 }
91 }
92 let vec_1 = mat_gso.get_column(0).unwrap();
93 assert_ne!(cmp, vec_1.dot_product(&vec_1).unwrap());
94 }
95
96 #[test]
98 fn gso_dependent_rows() {
99 let mat = MatQ::from_str("[[1, 2/7],[1, 2/7],[10, -2],[0, 4],[0, 0]]").unwrap();
100
101 let mat_gso = mat.gso();
102
103 let cmp = Q::ZERO;
104 for i in 0..2 {
105 let vec_i = mat_gso.get_column(i).unwrap();
106 assert_ne!(cmp, vec_i.dot_product(&vec_i).unwrap());
107 for j in i + 1..2 {
108 let vec_j = mat_gso.get_column(j).unwrap();
109 assert_eq!(cmp, vec_i.dot_product(&vec_j).unwrap());
110 }
111 }
112 }
113
114 #[test]
116 fn gso_large_values() {
117 let mat = MatQ::from_str(&format!(
118 "[[1, {}/7, 2],[1, 2/{}, 10],[10, -2, 8]]",
119 i64::MAX,
120 i64::MAX
121 ))
122 .unwrap();
123
124 let mat_gso = mat.gso();
125
126 let cmp = Q::ZERO;
127 for i in 0..3 {
128 let vec_i = mat_gso.get_column(i).unwrap();
129 assert_ne!(cmp, vec_i.dot_product(&vec_i).unwrap());
130 for j in i + 1..3 {
131 let vec_j = mat_gso.get_column(j).unwrap();
132 assert_eq!(cmp, vec_i.dot_product(&vec_j).unwrap());
133 }
134 }
135 }
136
137 #[test]
139 fn gso_edge_cases() {
140 let mat_1 = MatQ::from_str("[[1]]").unwrap();
141 let mat_2 = MatQ::from_str("[[1, 2/2, 3/7]]").unwrap();
142 let mat_3 = MatQ::from_str("[[1],[2/2],[3/7]]").unwrap();
143
144 let mat_1_gso = mat_1.gso();
145 let mat_2_gso = mat_2.gso();
146 let mat_3_gso = mat_3.gso();
147
148 assert_eq!(Q::ONE, mat_1_gso.get_entry(0, 0).unwrap());
149
150 let cmp = Q::ZERO;
151 for i in 0..3 {
152 for j in i + 1..3 {
153 let vec_i = mat_2_gso.get_column(i).unwrap();
154 let vec_j = mat_2_gso.get_column(j).unwrap();
155 assert_eq!(cmp, vec_i.dot_product(&vec_j).unwrap());
156 }
157 }
158 let vec_1 = mat_2_gso.get_column(0).unwrap();
159 assert_ne!(cmp, vec_1.dot_product(&vec_1).unwrap());
160
161 assert_eq!(mat_3, mat_3_gso);
162 }
163}