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