1 /* Copyright (c) 1997-2021
2 Ewgenij Gawrilow, Michael Joswig, and the polymake team
3 Technische Universität Berlin, Germany
4 https://polymake.org
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version: http://www.gnu.org/licenses/gpl.txt.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 --------------------------------------------------------------------------------
16 */
17
18 #pragma once
19
20 #include "polymake/Matrix.h"
21 #include "polymake/Vector.h"
22 #include "polymake/Rational.h"
23 #include "polymake/linalg.h"
24 #include "polymake/Smith_normal_form.h"
25
26 namespace polymake { namespace common {
27
28 template <typename TVector>
is_integral(const GenericVector<TVector,Rational> & V)29 bool is_integral(const GenericVector<TVector, Rational>& V)
30 {
31 for (auto x=entire(V.top()); !x.at_end(); ++x)
32 if (denominator(*x) != 1) return false;
33 return true;
34 }
35
36 template <typename TMatrix>
37 typename std::enable_if<TMatrix::is_flat, bool>::type
is_integral(const GenericMatrix<TMatrix,Rational> & M)38 is_integral(const GenericMatrix<TMatrix, Rational>& M)
39 {
40 return is_integral(concat_rows(M));
41 }
42
43 template <typename TMatrix>
44 typename std::enable_if<!TMatrix::is_flat, bool>::type
is_integral(const GenericMatrix<TMatrix,Rational> & M)45 is_integral(const GenericMatrix<TMatrix, Rational>& M)
46 {
47 for (auto r=entire(rows(M)); !r.at_end(); ++r)
48 if (!is_integral(*r)) return false;
49 return true;
50 }
51
52 namespace {
53
54 template <typename DstVector, typename SrcIterator>
store_eliminated_denominators(DstVector & vec,SrcIterator src,const Integer & LCM,std::false_type)55 void store_eliminated_denominators(DstVector& vec, SrcIterator src, const Integer& LCM, std::false_type)
56 {
57 for (auto dst=vec.begin(); !src.at_end(); ++src, ++dst)
58 if (!is_zero(*src))
59 *dst = div_exact(LCM, denominator(*src)) * numerator(*src);
60 }
61
62 template <typename DstVector, typename SrcIterator>
store_eliminated_denominators(DstVector & vec,SrcIterator src,const Integer & LCM,std::true_type)63 void store_eliminated_denominators(DstVector& vec, SrcIterator src, const Integer& LCM, std::true_type)
64 {
65 for (; !src.at_end(); ++src)
66 vec.push_back(src.index(), div_exact(LCM, denominator(*src)) * numerator(*src));
67 }
68
69 template <typename DstVector, typename SrcVector>
copy_eliminated_denominators(DstVector && vec,const SrcVector & src)70 void copy_eliminated_denominators(DstVector&& vec, const SrcVector& src)
71 {
72 store_eliminated_denominators(vec, entire(src), lcm(denominators(src)),
73 bool_constant<pm::check_container_feature<pure_type_t<DstVector>, pm::sparse>::value>());
74 }
75
76 }
77
78 template <typename TVector>
79 typename GenericVector<TVector, Integer>::persistent_type
eliminate_denominators(const GenericVector<TVector,Rational> & V)80 eliminate_denominators(const GenericVector<TVector, Rational>& V)
81 {
82 typename GenericVector<TVector, Integer>::persistent_type result(V.dim());
83 copy_eliminated_denominators(result, V.top());
84 return result;
85 }
86
87 template <typename TMatrix>
88 typename GenericMatrix<TMatrix, Integer>::persistent_type
eliminate_denominators_in_rows(const GenericMatrix<TMatrix,Rational> & M)89 eliminate_denominators_in_rows(const GenericMatrix<TMatrix, Rational>& M)
90 {
91 typename GenericMatrix<TMatrix, Integer>::persistent_type result(M.rows(), M.cols());
92 auto d=rows(result).begin();
93 for (auto s=entire(rows(M)); !s.at_end(); ++s, ++d)
94 copy_eliminated_denominators(*d, *s);
95 return result;
96 }
97
98 template <typename TMatrix>
99 typename GenericMatrix<TMatrix, Integer>::persistent_type
eliminate_denominators_entire(const GenericMatrix<TMatrix,Rational> & M)100 eliminate_denominators_entire(const GenericMatrix<TMatrix, Rational>& M)
101 {
102 typename GenericMatrix<TMatrix, Integer>::persistent_type result(M.rows(), M.cols());
103 copy_eliminated_denominators(concat_rows(result), concat_rows(M));
104 return result;
105 }
106
107 template <typename TMatrix>
108 typename GenericMatrix<TMatrix, Integer>::persistent_type
eliminate_denominators_entire_affine(const GenericMatrix<TMatrix,Rational> & M)109 eliminate_denominators_entire_affine(const GenericMatrix<TMatrix, Rational>& M)
110 {
111 typename GenericMatrix<TMatrix, Integer>::persistent_type result(M.rows(), M.cols());
112 if (M.rows() && M.cols()) {
113 if (M.cols() > 1)
114 copy_eliminated_denominators(concat_rows(result.minor(All, range_from(1))), concat_rows(M.minor(All, range_from(1))));
115 result.col(0) = numerators(M.col(0));
116 }
117 return result;
118 }
119
120 template <typename TVector>
121 typename std::enable_if<is_gcd_domain<typename TVector::element_type>::value, typename TVector::persistent_type>::type
divide_by_gcd(const GenericVector<TVector> & v)122 divide_by_gcd(const GenericVector<TVector>& v)
123 {
124 return div_exact(v, gcd(v));
125 }
126
127 template <typename TMatrix>
128 typename std::enable_if<is_gcd_domain<typename TMatrix::element_type>::value, typename TMatrix::persistent_type>::type
divide_by_gcd(const GenericMatrix<TMatrix> & M)129 divide_by_gcd(const GenericMatrix<TMatrix>& M)
130 {
131 // TODO: reformulate as a constructor taking a transformed iterator over rows using lambda expression.
132 typename TMatrix::persistent_type result(M.rows(), M.cols());
133 auto dst = rows(result).begin();
134 for (auto src = entire(rows(M)); !src.at_end(); ++src, ++dst)
135 *dst = div_exact(*src, gcd(*src));
136 return result;
137 }
138
139
140 template <typename TMatrix>
141 typename std::enable_if<is_gcd_domain<typename TMatrix::element_type>::value, typename TMatrix::persistent_type>::type
primitive(const GenericMatrix<TMatrix> & M)142 primitive(const GenericMatrix<TMatrix>& M)
143 {
144 return divide_by_gcd(M);
145 }
146
147 template <typename TMatrix>
148 typename std::enable_if<is_gcd_domain<typename TMatrix::element_type>::value, typename TMatrix::persistent_type>::type
primitive_affine(const GenericMatrix<TMatrix> & M)149 primitive_affine(const GenericMatrix<TMatrix>& M)
150 {
151 return M.col(0) | divide_by_gcd(M.minor(All, range_from(1)));
152 }
153
154 template <typename TMatrix>
155 typename GenericMatrix<TMatrix, Integer>::persistent_type
primitive(const GenericMatrix<TMatrix,Rational> & M)156 primitive(const GenericMatrix<TMatrix, Rational>& M)
157 {
158 typename GenericMatrix<TMatrix, Integer>::persistent_type result = eliminate_denominators_in_rows(M);
159 for (auto r=entire(rows(result)); !r.at_end(); ++r)
160 r->div_exact(gcd(*r));
161 return result;
162 }
163
164 template <typename TMatrix>
165 typename GenericMatrix<TMatrix, Integer>::persistent_type
primitive_affine(const GenericMatrix<TMatrix,Rational> & M)166 primitive_affine(const GenericMatrix<TMatrix, Rational>& M)
167 {
168 if (!is_integral(M.col(0)))
169 throw std::runtime_error("homogeneous coordinates not integral");
170
171 return numerators(M.col(0)) | primitive(M.minor(All, range_from(1)));
172 }
173
174
175 template <typename TVector>
176 typename std::enable_if<is_gcd_domain<typename TVector::element_type>::value, typename TVector::persistent_type>::type
primitive(const GenericVector<TVector> & v)177 primitive(const GenericVector<TVector>& v)
178 {
179 return divide_by_gcd(v);
180 }
181
182 template <typename TVector>
183 typename std::enable_if<is_gcd_domain<typename TVector::element_type>::value, typename TVector::persistent_type>::type
primitive_affine(const GenericVector<TVector> & v)184 primitive_affine(const GenericVector<TVector>& v)
185 {
186 return v.top()[0] | divide_by_gcd(v.slice(range_from(1)));
187 }
188
189 template <typename TVector>
190 typename GenericVector<TVector, Integer>::persistent_type
primitive(const GenericVector<TVector,Rational> & v)191 primitive(const GenericVector<TVector, Rational>& v)
192 {
193 typename GenericVector<TVector, Integer>::persistent_type result = eliminate_denominators(v);
194 result.div_exact(gcd(result));
195 return result;
196 }
197
198 template <typename TVector>
199 typename GenericVector<TVector, Integer>::persistent_type
primitive_affine(const GenericVector<TVector,Rational> & v)200 primitive_affine(const GenericVector<TVector, Rational>& v)
201 {
202 if (denominator(v.top()[0]) != 1)
203 throw std::runtime_error("homogeneous coordinate not integral");
204
205 return numerator(v.top()[0]) | primitive(v.slice(range_from(1)));
206 }
207
208 template <typename TMatrix>
209 typename GenericMatrix<TMatrix, Integer>::persistent_type
lattice_basis(const GenericMatrix<TMatrix,Integer> & gens)210 lattice_basis(const GenericMatrix<TMatrix, Integer>& gens)
211 {
212 const SmithNormalForm<Integer> SNF = smith_normal_form(gens);
213 return (SNF.form * SNF.right_companion).minor(range(0, SNF.rank-1),All);
214 }
215
216 } }
217
218
219 // Local Variables:
220 // mode:C++
221 // c-basic-offset:3
222 // indent-tabs-mode:nil
223 // End:
224