1 /* RegularTriangulationWith4ti2.cpp -- Triangulate with 4ti2
2
3 Copyright 2007 Matthias Koeppe
4
5 This file is part of LattE.
6
7 LattE is free software; you can redistribute it and/or modify it
8 under the terms of the version 2 of the GNU General Public License
9 as published by the Free Software Foundation.
10
11 LattE is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with LattE; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20
21 #include <iostream>
22
23 // From 4ti2:
24 #include "groebner/BitSet.h"
25 #include "groebner/VectorArrayStream.h"
26 #include "groebner/LatticeBasis.h"
27 #include "groebner/RayAlgorithm.h"
28 #include "groebner/HermiteAlgorithm.h"
29
30 // From LattE:
31 #include "latte_4ti2.h"
32 #include "dual.h"
33 #include "print.h"
34 #include "triangulation/RegularTriangulationWith4ti2.h"
35
36 using namespace _4ti2_;
37
38 listCone *
cone_from_ray_BitSet(vector<listVector * > & rays,const BitSet & ray_set,Vertex * vertex)39 cone_from_ray_BitSet(vector<listVector *> &rays, const BitSet &ray_set,
40 Vertex *vertex)
41 {
42 listCone *c = createListCone();
43 c->vertex = new Vertex(*vertex);
44 vector<listVector *>::iterator i;
45 int j;
46 for (i = rays.begin(), j = 0; i != rays.end(); ++i, j++)
47 {
48 if (ray_set[j])
49 {
50 c->rays = new listVector((*i)->first, c->rays, (*i)->index_hint);
51 }
52 }
53 return c;
54 }
55
lindep_heights_p(listCone * cone,BarvinokParameters * Parameters,const vector<mpz_class> & heights,bool print=false)56 static bool lindep_heights_p(listCone *cone, BarvinokParameters *Parameters,
57 const vector<mpz_class> &heights, bool print = false)
58 {
59 int num_rays = lengthListVector(cone->rays);
60 /* Check for linearly dependent height vector. */
61 VectorArray *ray_column_matrix = rays_to_transposed_4ti2_VectorArray(
62 cone->rays, Parameters->Number_of_Variables,
63 /* extra_rows: */1);
64 if (print)
65 cout << "Before: " << endl << *ray_column_matrix << endl;
66 int rank = upper_triangle(*ray_column_matrix,
67 Parameters->Number_of_Variables, num_rays);
68 if (print)
69 cout << "After: " << endl << *ray_column_matrix << endl;
70 int i;
71 for (i = 0; i < num_rays; i++)
72 (*ray_column_matrix)[rank][i] = heights[i];
73 if (print)
74 cout << "With heights: " << endl << *ray_column_matrix << endl;
75 int new_rank = upper_triangle(*ray_column_matrix, rank + 1, num_rays);
76 if (print)
77 cout << "Finally: " << endl << *ray_column_matrix << endl;
78 delete ray_column_matrix;
79 if (new_rank == rank)
80 return true;
81 else
82 return false;
83 }
84
triangulate_cone_with_4ti2(listCone * cone,BarvinokParameters * Parameters,height_function_type height_function,void * height_function_data,ConeConsumer & consumer)85 void triangulate_cone_with_4ti2(listCone *cone, BarvinokParameters *Parameters,
86 height_function_type height_function, void *height_function_data,
87 ConeConsumer &consumer)
88 {
89 Parameters->num_triangulations++;
90 // Copy rays into an array, so we can index them.
91 int num_rays = lengthListVector(cone->rays);
92 vector<listVector *> rays_array = ray_array(cone);
93 vector<mpz_class> heights(num_rays);
94 /* Compute the heights. */
95 int i;
96 mpq_class first_height;
97 bool seen_different_heights = false;
98 for (i = 0; i < num_rays; i++)
99 {
100 mpq_class height;
101 height_function(height.get_mpq_t(), rays_array[i]->first,
102 height_function_data);
103 if (i == 0)
104 first_height = height;
105 else if (first_height != height)
106 seen_different_heights = true;
107 heights[i] = height.get_num();
108 }
109
110 if (!seen_different_heights)
111 {
112 /* This will be a trivial polyhedral subdivision, so just return
113 a copy of the cone. */
114 //cerr << "Trivial test: Lifting heights yield trivial polyhedral subdivision." << endl;
115 Parameters->num_triangulations_with_trivial_heights++;
116 consumer.ConsumeCone(copyCone(cone));
117 return;
118 }
119
120 bool lindep_height = lindep_heights_p(cone, Parameters, heights, false);
121 if (lindep_height)
122 {
123 //cerr << "Rank test: Lifting heights yield trivial polyhedral subdivision." << endl;
124 Parameters->num_triangulations_with_dependent_heights++;
125 #ifndef DEBUG_RANKTEST
126 consumer.ConsumeCone(copyCone(cone));
127 return;
128 #endif
129 }
130
131 /* Create a matrix from the rays, with 1 extra coordinates
132 at the front for the lifting, and also slack variables.
133 (4ti2 does not use a homogenization coordinate.) */
134 int lifted_dim = Parameters->Number_of_Variables + 1 + 1 + num_rays;
135 BitSet *rs = new BitSet(lifted_dim);
136 VectorArray *matrix = rays_to_4ti2_VectorArray(cone->rays,
137 Parameters->Number_of_Variables,
138 /* num_homogenization_vars: */1 + 1 + num_rays,
139 /* num_extra_rows: */1);
140 /* Add identity matrix for the slack variables (including a slack
141 variable for the extra ray). */
142 {
143 int i;
144 for (i = 0; i < num_rays + 1; i++)
145 {
146 (*matrix)[i][i] = 1;
147 rs->set(i);
148 }
149 }
150
151 int I_width = num_rays + 1;
152
153 /* Extra row: `vertical' ray -- This kills all upper facets.
154 See Verdoolaege, Woods, Bruynooghe, Cools (2005). */
155 (*matrix)[num_rays][I_width] = 1;
156
157 /* Put in the heights. */
158 for (i = 0; i < num_rays; i++)
159 {
160 (*matrix)[i][I_width] = heights[i];
161 }
162
163 /* Output of the file -- for debugging. */
164 if (Parameters->debug_triangulation)
165 {
166 std::ofstream file("lifted_cone_for_4ti2_triangulation");
167 file << matrix->get_number() << " " << lifted_dim << endl;
168 print(file, *matrix, 0, lifted_dim);
169 cerr << "Created file `lifted_cone_for_4ti2_triangulation'" << endl;
170 }
171 #if 0
172 VectorArray *facets = new VectorArray(0, matrix->get_size());
173 lattice_basis(*matrix, *facets); // too slow.
174 #else
175 int numvars_plus_1 = Parameters->Number_of_Variables + 1;
176 VectorArray *facets = new VectorArray(numvars_plus_1, matrix->get_size());
177 /* Our matrix is of the form (I w A), so the kernel has a basis of
178 the form ((-w -A)^T I). */
179 for (i = 0; i < numvars_plus_1; i++)
180 {
181 int j;
182 for (j = 0; j < I_width; j++)
183 (*facets)[i][j] = -(*matrix)[j][I_width + i];
184 (*facets)[i][I_width + i] = 1;
185 }
186 #endif
187 #if 0
188 cerr << "Facets: " << *facets << endl;
189 #endif
190
191 VectorArray* subspace = new VectorArray(0, matrix->get_size());
192 RayAlgorithm algorithm;
193
194 //Redirect cout to cerr (when calling 4ti2's triangulation function).
195 streambuf * cout_strbuf(cout.rdbuf()); //keep copy of the real cout.
196 if ( Parameters->debug_triangulation == false)
197 {
198 cout.rdbuf(cerr.rdbuf()); //change cout to cerr
199 }
200 algorithm.compute(*matrix, *facets, *subspace, *rs);
201 cout.rdbuf(cout_strbuf); //revert cout back to cout!
202
203 if (Parameters->debug_triangulation)
204 {
205 std::ofstream file("4ti2_triangulation_output");
206 file << facets->get_number() << " " << lifted_dim << "\n";
207 print(file, *facets, 0, lifted_dim);
208 cerr << "Created file `4ti2_triangulation_output'" << endl;
209 }
210
211 /* Walk through all facets. (Ignore all equalities in *subspace.)
212 */
213 int num_cones_created = 0;
214 int num_equalities = subspace->get_number();
215 int num_facets = facets->get_number();
216 int true_dimension = Parameters->Number_of_Variables - num_equalities;
217 BitSet incidence(num_rays);
218 consumer.SetNumCones(num_facets); // estimate is enough
219 for (i = 0; i < num_facets; i++)
220 {
221 /* We ignore facets that are incident with the extra vertical
222 ray. */
223 if ((*facets)[i][I_width] != 0)
224 {
225 /* All other facets give a face of the triangulation. */
226 /* Find incident rays.
227 They are the rays whose corresponding slack variables are
228 zero. */
229 incidence.zero();
230 int j;
231 for (j = 0; j < num_rays; j++)
232 {
233 if ((*facets)[i][j] == 0)
234 {
235 /* Incident! */
236 incidence.set(j);
237 }
238 }
239 /* Create the cone from the incidence information. */
240 listCone *c = cone_from_ray_BitSet(rays_array, incidence,
241 cone->vertex);
242 /* Is a cone of the triangulation -- check it is simplicial */
243 int c_num_rays = incidence.count();
244 if (c_num_rays > true_dimension
245 && !Parameters->nonsimplicial_subdivision)
246 {
247 cerr << "Found non-simplicial cone (" << c_num_rays << "rays) "
248 << "in polyhedral subdivision, triangulating it recursively."
249 << endl;
250 /* In the refinement step, always fall back to using a
251 random height vector. */
252 triangulate_cone_with_4ti2(c, Parameters, random_height,
253 &Parameters->triangulation_max_height, consumer);
254 } else if (c_num_rays < true_dimension)
255 {
256 cerr
257 << "Lower-dimensional cone in polyhedral subdivision, should not happen."
258 << endl;
259 abort();
260 } else
261 {
262 consumer.ConsumeCone(c);
263 num_cones_created++;
264 }
265 }
266 }
267
268 #ifdef DEBUG_RANKTEST
269 if (lindep_height && num_cones_created != 1)
270 {
271 cerr << "Created non-trivial subdivision, though heights were dependent?!" << endl;
272 cerr << "Matrix: " << endl << *matrix << endl;
273 lindep_heights_p(cone, Parameters, heights, true);
274 abort();
275 }
276 #endif
277
278 delete facets;
279 delete subspace;
280 delete matrix;
281 delete rs;
282 }
283
random_regular_triangulation_with_4ti2(listCone * cone,BarvinokParameters * Parameters,ConeConsumer & consumer)284 void random_regular_triangulation_with_4ti2(listCone *cone,
285 BarvinokParameters *Parameters, ConeConsumer &consumer)
286 {
287 if (Parameters->triangulation_prescribed_height_data != NULL)
288 {
289 triangulate_cone_with_4ti2(cone, Parameters, prescribed_height,
290 Parameters->triangulation_prescribed_height_data, consumer);
291 } else if (Parameters->triangulation_bias >= 0)
292 {
293 triangulate_cone_with_4ti2(cone, Parameters, biased_random_height,
294 &Parameters->triangulation_bias, consumer);
295 } else
296 {
297 triangulate_cone_with_4ti2(cone, Parameters, random_height,
298 &Parameters->triangulation_max_height, consumer);
299 }
300 }
301
refined_delone_triangulation_with_4ti2(listCone * cone,BarvinokParameters * Parameters,ConeConsumer & consumer)302 void refined_delone_triangulation_with_4ti2(listCone *cone,
303 BarvinokParameters *Parameters, ConeConsumer &consumer)
304 {
305 triangulate_cone_with_4ti2(cone, Parameters, delone_height, NULL, consumer);
306 }
307