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