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 /** @file Double_Description.h
19 @brief Implementation of files for tropical double description
20 */
21
22 #pragma once
23
24 #include "polymake/Rational.h"
25 #include "polymake/TropicalNumber.h"
26 #include "polymake/Array.h"
27 #include "polymake/Matrix.h"
28 #include "polymake/ListMatrix.h"
29 #include "polymake/Vector.h"
30 #include "polymake/Set.h"
31 #include "polymake/tropical/covectors.h"
32 #include "polymake/tropical/thomog.h"
33
34 namespace polymake {
35 namespace tropical {
36
37 /*
38 * @brief: check if point is contained in a tropical cone defined by
39 * inequalities which are given by their apices and infeasible sectors
40 */
41 template <typename VectorTop, typename MatrixTop, typename Addition, typename Scalar>
is_contained(const GenericVector<VectorTop,TropicalNumber<Addition,Scalar>> & point,const GenericMatrix<MatrixTop,TropicalNumber<Addition,Scalar>> & apices,const Array<Set<Int>> & sectors)42 bool is_contained(const GenericVector<VectorTop, TropicalNumber<Addition, Scalar>>& point,
43 const GenericMatrix<MatrixTop, TropicalNumber<Addition, Scalar>>& apices,
44 const Array<Set<Int>>& sectors)
45 {
46 Int row_index = 0;
47 const IncidenceMatrix<> M(generalized_apex_covector(point, apices));
48 for (const auto& r : rows(M)) {
49 if (incl(r, sectors[row_index]) <= 0)
50 return false;
51 ++row_index;
52 }
53 return true;
54 }
55
56 /*
57 * @brief: check if a point fulfills the inequality system A x <= B x for min resp. A x >= B x for max
58 */
59 template <typename VectorTop, typename Matrix1, typename Matrix2, typename Addition, typename Scalar>
is_contained(const GenericVector<VectorTop,TropicalNumber<Addition,Scalar>> & point,const GenericMatrix<Matrix1,TropicalNumber<Addition,Scalar>> & lhs,const GenericMatrix<Matrix2,TropicalNumber<Addition,Scalar>> & rhs)60 bool is_contained(const GenericVector<VectorTop, TropicalNumber<Addition, Scalar>>& point,
61 const GenericMatrix<Matrix1, TropicalNumber<Addition, Scalar>>& lhs,
62 const GenericMatrix<Matrix2, TropicalNumber<Addition, Scalar>>& rhs)
63 {
64 for (Int i = 0; i < lhs.rows(); ++i) {
65 if (point * lhs > point * rhs) return false;
66 }
67 return true;
68 }
69
70 /*
71 * @brief: convert inequality A x <= B x for min resp. A x >= B x for max
72 * to the description by
73 * apices and INfeasible sectors. Here, B is on the INfeasible side.
74 */
75 template <typename Addition, typename Scalar>
76 std::pair<Matrix<TropicalNumber<Addition, Scalar>>, Array<Set<Int>>>
matrixPair2apexSet(const Matrix<TropicalNumber<Addition,Scalar>> & A,const Matrix<TropicalNumber<Addition,Scalar>> & B)77 matrixPair2apexSet(const Matrix<TropicalNumber<Addition, Scalar>>& A,
78 const Matrix<TropicalNumber<Addition,Scalar>>& B)
79 {
80 using TNumber = TropicalNumber<Addition, Scalar>;
81 Array<Set<Int>> sectors(A.rows());
82 Matrix<TNumber> W(A.rows(), A.cols());
83 TNumber entry;
84 for (Int i = 0; i < A.rows(); ++i) {
85 for (Int j = 0; j < A.cols(); ++j) {
86 if (A(i,j) != B(i,j)) {
87 entry = A(i,j) + B(i,j);
88 W(i,j) = entry;
89 if (entry == B(i,j)) sectors[i] += j;
90 }
91 }
92 }
93 return { W, sectors };
94 }
95
96 /*
97 * @brief: convert inequality A x <= B x for min resp. A x >= B x for max
98 * to the description by
99 * apices and INfeasible sectors. Here, B is on the INfeasible side.
100 */
101 template <typename Addition, typename Scalar>
102 std::pair<Matrix<TropicalNumber<Addition, Scalar>>, Array<Int>>
matrixPair2splitApices(const Matrix<TropicalNumber<Addition,Scalar>> & A,const Matrix<TropicalNumber<Addition,Scalar>> & B)103 matrixPair2splitApices(const Matrix<TropicalNumber<Addition, Scalar>>& A,
104 const Matrix<TropicalNumber<Addition, Scalar>>& B)
105 {
106 const Int n = A.rows(), d = A.cols();
107 if (n != B.rows())
108 throw std::runtime_error("dimension mismatch for inequality system: different number of rows");
109 if (d != B.cols())
110 throw std::runtime_error("dimension mismatch for inequality system: different number of columns");
111
112 using TNumber = TropicalNumber<Addition,Scalar>;
113 std::list<Int> negative_indices;
114 ListMatrix<Vector<TNumber>> W(0, A.cols());
115 for (Int i = 0; i < n; ++i) {
116 for (Int j = 0; j < d; ++j) {
117 if (A(i,j) != A(i,j) + B(i,j)) {
118 Vector<TNumber> modified_row = A.row(i);
119 modified_row[j] = B(i,j);
120 negative_indices.push_back(j);
121 W /= modified_row;
122 }
123 }
124 }
125 return { Matrix<TNumber>(W), Array<Int>(W.rows(), negative_indices.begin()) };
126 }
127
128
129 /*
130 * @brief: reduce a set of generators of a tropical cone to the
131 * extremal generators
132 *
133 */
134 template <typename MatrixTop, typename Addition, typename Scalar>
135 Matrix<TropicalNumber<Addition, Scalar>>
extremals_from_generators(const GenericMatrix<MatrixTop,TropicalNumber<Addition,Scalar>> & generators)136 extremals_from_generators(const GenericMatrix<MatrixTop, TropicalNumber<Addition, Scalar>>& generators)
137 {
138 using TNumber = TropicalNumber<Addition,Scalar>;
139 const Int n = generators.rows(), dim = generators.cols();
140
141 ListMatrix<Vector<TNumber>> extremals;
142
143 // removing double points
144 Set<Int> reduced_generators;
145 for (Int i = 0; i < n; ++i) {
146 bool redundant = false;
147 for (auto r = entire(rows(generators.minor(reduced_generators,All))); !r.at_end(); ++r) {
148 if (dim == single_covector(generators[i],(*r)).size()) {
149 redundant = true;
150 break;
151 }
152 }
153 if (!redundant)
154 reduced_generators += i;
155 }
156
157 for (auto r = entire(rows(generators.minor(reduced_generators,All))); !r.at_end(); ++r) {
158 bool is_extremal = false;
159
160 // checking covector criterion for extremality, using exposedness
161 for (auto coord = entire(rows(single_covector((*r), generators.minor(reduced_generators,All)))); !coord.at_end(); ++coord) {
162 if (coord->size() == 1) {
163 is_extremal = true;
164 break;
165 }
166 }
167 if (is_extremal)
168 extremals /= *r;
169 }
170 return extremals;
171 }
172
173
174 /*
175 * @brief: compute the extremals of a tropical cone given by the
176 * intersection of a tropical halfspace with another tropical cone
177 * which is given by its extremals.
178 */
179 template <typename MatrixTop, typename Vector1, typename Vector2, typename Addition, typename Scalar>
180 Matrix<TropicalNumber<Addition, Scalar>>
intersection_extremals(const GenericMatrix<MatrixTop,TropicalNumber<Addition,Scalar>> & generators,const GenericVector<Vector1,TropicalNumber<Addition,Scalar>> & feasible_side,const GenericVector<Vector2,TropicalNumber<Addition,Scalar>> & infeasible_side)181 intersection_extremals(const GenericMatrix<MatrixTop, TropicalNumber<Addition, Scalar>>& generators,
182 const GenericVector<Vector1, TropicalNumber<Addition, Scalar>>& feasible_side,
183 const GenericVector<Vector2, TropicalNumber<Addition, Scalar>>& infeasible_side)
184 {
185 using TNumber = TropicalNumber<Addition,Scalar>;
186
187 Set<Int> remaining_generators;
188 Int r_index = 0;
189
190 // check for all generators if they are contained in the halfspace given by the pair
191 // (feasible_side, infeasible_side)
192 for (const auto& r : rows(generators)) {
193 if (Addition::orientation()*(feasible_side*r).compare(infeasible_side*r) <= 0)
194 remaining_generators += r_index;
195 ++r_index;
196 }
197 Set<Vector<TNumber>> new_points;
198 for (auto g = entire(rows(generators.minor(remaining_generators,All))); !g.at_end(); ++g) {
199 for (auto h = entire(rows(generators.minor(~remaining_generators,All))); !h.at_end(); ++h) {
200 Vector<TNumber> k = (infeasible_side * (*h)) * (*g) + (feasible_side * (*g)) * (*h);
201 new_points += normalized_first(k);
202 }
203 }
204
205 Matrix<TNumber> new_generators(new_points.size(), feasible_side.dim(), entire(new_points));
206 new_generators /= generators.minor(remaining_generators, All);
207 return extremals_from_generators(new_generators);
208 }
209
210
211 /*
212 * @brief: compute the extremals of a tropical cone given
213 * as the intersection of tropical halfspaces
214 *
215 */
216 template <typename Matrix1, typename Matrix2, typename Addition, typename Scalar>
217 Matrix<TropicalNumber<Addition, Scalar>>
extremals_from_halfspaces(const GenericMatrix<Matrix1,TropicalNumber<Addition,Scalar>> & feasible_side,const GenericMatrix<Matrix2,TropicalNumber<Addition,Scalar>> & infeasible_side)218 extremals_from_halfspaces(const GenericMatrix<Matrix1, TropicalNumber<Addition, Scalar>>& feasible_side,
219 const GenericMatrix<Matrix2, TropicalNumber<Addition, Scalar>>& infeasible_side)
220 {
221 using TNumber = TropicalNumber<Addition,Scalar>;
222
223 if (infeasible_side.rows() != feasible_side.rows())
224 throw std::runtime_error("dimension mismatch for inequality system: different number of rows");
225
226 const Int n_halfspaces = infeasible_side.rows();
227
228 Matrix<TNumber> extremals(unit_matrix<TNumber>(infeasible_side.cols()));
229
230 for (Int i = 0; i < n_halfspaces; ++i) {
231 extremals = intersection_extremals(extremals, feasible_side[i], infeasible_side[i]);
232 }
233 return extremals;
234 }
235
236
237 /*
238 * @brief: compute the extremals of a monomial tropical cone given by the
239 * intersection of a tropical halfspace (defined via nondominated point) with a monomial tropical cone
240 * which is given by generators and apices.
241 */
242 template <typename Matrix1, typename Matrix2, typename VectorTop, typename Addition, typename Scalar>
243 Matrix<TropicalNumber<Addition, Scalar>>
monoextremals(const GenericMatrix<Matrix1,TropicalNumber<Addition,Scalar>> & generators,const GenericMatrix<Matrix2,TropicalNumber<Addition,Scalar>> & apices,const GenericVector<VectorTop,Scalar> & non_dominated_point)244 monoextremals(const GenericMatrix<Matrix1, TropicalNumber<Addition, Scalar>>& generators,
245 const GenericMatrix<Matrix2, TropicalNumber<Addition, Scalar>>& apices,
246 const GenericVector<VectorTop, Scalar>& non_dominated_point)
247 {
248 using TNumber = TropicalNumber<Addition,Scalar>;
249
250 Set<Int> remaining_generators;
251 Int r_index = 0;
252 Vector<TNumber> infeasible_side(non_dominated_point.dim()+1);
253 infeasible_side[0] = TNumber::one();
254
255 Vector<TNumber> feasible_side(non_dominated_point.dim()+1);
256 feasible_side.slice(range_from(1)) = -non_dominated_point;
257
258 Vector<TNumber> new_apex((0|non_dominated_point));
259
260 // check for all generators if they are contained in the halfspace given by the pair
261 // (feasible_side, infeasible_side)
262 for (const auto r : rows(generators)) {
263 if (Addition::orientation()*(feasible_side*r).compare(infeasible_side*r) <= 0)
264 remaining_generators += r_index;
265 ++r_index;
266 }
267
268 Set<Vector<TNumber>> new_generators;
269
270 for (auto g = entire(rows(generators.minor(remaining_generators, All))); !g.at_end(); ++g) {
271 for (auto h = entire(rows(generators.minor(~remaining_generators,All))); !h.at_end(); ++h) {
272 Vector<TNumber> k = (infeasible_side * (*h)) * (*g) + (feasible_side * (*g)) * (*h);
273
274 // the next loop should determine if k is redundant; should probably be simplified -- check if pairwise incomparable
275 Set<Int> covered_sectors;
276 Set<Int> apex_sectors;
277 for (auto apex : rows(apices)) {
278 // why does (apices/new_apex) not work??
279 apex_sectors = single_covector(apex, k);
280 if ((apex_sectors.contains(0)) & (apex_sectors.size()==2)) {
281 covered_sectors += apex_sectors;
282 }
283 }
284 // FIXME: this is a specific check of extremality for monomial tropical cones -- maybe here is a mistake
285 apex_sectors = single_covector(new_apex, k);
286 if (apex_sectors.contains(0)) {
287 covered_sectors += apex_sectors;
288 }
289 if (covered_sectors == support(k)) {
290 new_generators += normalized_first(k);
291 }
292 }
293 }
294 Matrix<TNumber> all_generators(new_generators.size(), new_apex.dim(), entire(new_generators));
295
296 return generators.minor(remaining_generators,All)/all_generators;
297 }
298
299
300 /*
301 * @brief: determine the dual generators of dehomogenized monomial generators
302 *
303 * @return: a pair of dual generators and the incidences with the primal generators
304 */
305 template <typename MatrixTop, typename Scalar>
306 std::pair<Matrix<TropicalNumber<Min, Scalar>>, IncidenceMatrix<>>
monomial_dual_description(const GenericMatrix<MatrixTop,Scalar> & monomial_generators)307 monomial_dual_description(const GenericMatrix<MatrixTop, Scalar>& monomial_generators)
308 {
309 using TNumber = TropicalNumber<Min, Scalar>;
310
311 Int dim = monomial_generators.cols();
312
313 Matrix<TNumber> gen(unit_matrix<TNumber>(dim+1));
314 ListMatrix<Vector<TNumber>> apices;
315
316 for (const auto& mg : rows(monomial_generators)) {
317 gen = monoextremals(gen, apices, mg);
318 const auto new_apex = TNumber::one() | convert_to<TNumber>(mg);
319 apices /= new_apex;
320 }
321
322 ListMatrix<Vector<TNumber>> finite_gen;
323
324 // select only those generators with first coord 0
325 for (const auto& g : rows(gen)) {
326 if (g[0]==0) finite_gen /= g;
327 }
328
329 // compute the incidences of primal and dual generators
330 IncidenceMatrix<> vif(monomial_generators.rows(), finite_gen.rows());
331 Int i = 0;
332 for (const auto& mg : rows(monomial_generators)) {
333 Int j = 0;
334 for (const auto& dg : rows(finite_gen)) {
335 Vector<Scalar> sg(dg.slice(range_from(1)));
336 if (accumulate(sg-mg, operations::min()) == static_cast<const Scalar&>(dg[0]))
337 vif(i, j) = true;
338 ++j;
339 }
340 ++i;
341 }
342
343 return { Matrix<TNumber>(finite_gen), vif };
344 }
345
346 } }
347
348
349 // Local Variables:
350 // mode:C++
351 // c-basic-offset:3
352 // indent-tabs-mode:nil
353 // End:
354