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 #include "polymake/client.h"
19 #include "polymake/Array.h"
20 #include "polymake/Rational.h"
21 #include "polymake/Set.h"
22 #include "polymake/IncidenceMatrix.h"
23 #include "polymake/Matrix.h"
24 #include "polymake/ListMatrix.h"
25 #include "polymake/TropicalNumber.h"
26 #include "polymake/linalg.h"
27 #include "polymake/fan/tight_span.h"
28 #include "polymake/graph/lattice_builder.h"
29
30 namespace polymake { namespace tropical {
31
32 using namespace graph;
33 using namespace graph::lattice;
34 using namespace fan;
35
36 template <typename Addition>
linear_space(BigObject valuated_matroid)37 BigObject linear_space(BigObject valuated_matroid)
38 {
39 const BigObject polytope = valuated_matroid.give("POLYTOPE");
40 const Matrix<Rational> &vertices = polytope.give("VERTICES");
41 const auto no_front_set = sequence(1,vertices.cols()-1);
42 const auto vertices_no_front = vertices.minor(All,no_front_set);
43 const Int n = valuated_matroid.give("N_ELEMENTS");
44 Int n_facets = valuated_matroid.give("N_BASES");
45 const Vector<TropicalNumber<Addition> > &valuation = valuated_matroid.give("VALUATION_ON_BASES");
46 const Vector<Rational> rational_valuation(valuation);
47 const Array<Set<Int>>& subdivision = valuated_matroid.give("SUBDIVISION");
48 const Array<Array<Set<Int>>>& split_flacets = valuated_matroid.give("SPLIT_FLACETS");
49 const Int polytope_dim = polytope.call_method("DIM");
50 ListMatrix<Vector<Rational> > new_vertices;
51
52 // Check absence of loops
53 const Int n_matroid_loops = valuated_matroid.give("N_LOOPS");
54 if (n_matroid_loops > 0) {
55 // an empty cycle
56 return BigObject("Cycle", mlist<Addition>(),
57 "PROJECTIVE_VERTICES", Matrix<Rational>(0, n+1),
58 "MAXIMAL_POLYTOPES", Array<Set<Int>>(),
59 "PROJECTIVE_AMBIENT_DIM", n-1,
60 "WEIGHTS", Vector<Integer>());
61 }
62
63 // excluded faces (those with loops):
64 Array<Set<Int>> including_bases(n);
65 std::list<Set<Int>> non_including_bases(n);
66 const auto total_list = sequence(0,n_facets);
67 auto non_bases_it = entire(non_including_bases);
68 auto bases_it = entire(including_bases);
69 for (auto vcol = entire(cols(vertices_no_front)); !vcol.at_end();
70 ++vcol, ++bases_it, ++non_bases_it) {
71 *bases_it = support(*vcol);
72 *non_bases_it = total_list - *bases_it;
73 }
74
75 // Vertices of the tight span (for each max. cell in the subdivision):
76 const auto& equations = -rational_valuation | vertices_no_front;
77 for (const auto& cell : subdivision) {
78 auto nspace = null_space( equations.minor(cell,All));
79 auto ncol = entire(nspace.col(0));
80 for (auto nrows = entire(rows(nspace)); !nrows.at_end(); ++nrows, ++ncol) {
81 if (!ncol->is_zero()) {
82 new_vertices /= *nrows / *ncol;
83 break;
84 }
85 }
86 }
87
88 // stack the 'loop-free' facets and add a ray for each such facet
89 RestrictedIncidenceMatrix<> flacets(subdivision.size(), rowwise(), entire(subdivision));
90 Int i = 1;
91 for (auto incl_base = entire(including_bases); !incl_base.at_end(); ++incl_base, ++i) {
92 const Int n_loops = attach_selector( cols(vertices_no_front.minor(*incl_base,All)), operations::is_zero()).size();
93 if (n_loops > 0 || rank( vertices.minor(*incl_base,All)) != polytope_dim) continue;
94
95 new_vertices /= (Addition::orientation() * unit_vector<Rational>(n+1,i));
96 flacets /= ( (*incl_base) + n_facets);
97 n_facets++;
98 }
99 for (auto rk = entire<indexed>(split_flacets); !rk.at_end(); ++rk) {
100 for (const auto& flacet : *rk) {
101 Vector<Rational> v(n);
102 v.slice(flacet).fill(1);
103 v = -rk.index() | v;
104 auto col_sum_supp = total_list - support(vertices * v);
105 if (rank( vertices.minor (col_sum_supp,All)) != polytope_dim) continue;
106
107 v[0] = 0;
108 flacets /= col_sum_supp + n_facets;
109 new_vertices /= Addition::orientation() * v;
110 ++n_facets;
111 }
112 }
113
114 // Build Hasse diagram
115 const IncidenceMatrix<> flacet_inc(std::move(flacets));
116 NoBoundaryCut cut( non_including_bases, flacet_inc);
117 BasicClosureOperator<> cop(flacet_inc.rows(), T(flacet_inc));
118 BasicDecorator<> dec(0, scalar2set(-1));
119 Lattice<BasicDecoration> hasse_diagram = lattice_builder::compute_lattice_from_closure<BasicDecoration>(
120 cop, cut, dec, 1, lattice_builder::Primal());
121 const Int n_max_polys = hasse_diagram.in_adjacent_nodes(hasse_diagram.top_node()).size();
122
123 // Build lineality space
124 const Array<Set<Int>>& ccomp = valuated_matroid.give("CONNECTED_COMPONENTS");
125 Matrix<Rational> lin_space(ccomp.size()-1, n+1);
126
127 auto lin_no_front = sequence(1, lin_space.cols()-1);
128 auto lin_space_no_front = lin_space.minor(All,lin_no_front);
129 auto lin_rows = entire(rows(lin_space_no_front));
130 auto cc = entire(ccomp);
131 if (!cc.at_end()) {
132 // We take all connected components but the first.
133 while (!(++cc).at_end()) {
134 lin_rows->slice(*cc).fill(1);
135 ++lin_rows;
136 }
137 }
138
139 return BigObject("Cycle", mlist<Addition>(),
140 "PROJECTIVE_VERTICES", new_vertices,
141 "HASSE_DIAGRAM", hasse_diagram,
142 "LINEALITY_SPACE", lin_space,
143 "WEIGHTS", ones_vector<Integer>(n_max_polys));
144 }
145
146 UserFunctionTemplate4perl("# @category Tropical linear spaces"
147 "# This computes the tropical linear space (with the coarsest structure) associated to a valuated matroid."
148 "# If you have a trivial valuation, it is highly recommended, you use"
149 "# [[matroid_fan]] instead."
150 "# @param matroid::ValuatedMatroid<Addition,Rational> A valuated matroid, whose value group must be the rationals."
151 "# @return Cycle<Addition>",
152 "linear_space<Addition>(matroid::ValuatedMatroid<Addition>)");
153 } }
154