blob: ca9469f984200d30bac105a08cd51c017dd017ea [file] [log] [blame]
Austin Schuh405fa6c2015-09-06 18:13:55 -07001/* cddlib.c: cdd library (library version of cdd)
2 written by Komei Fukuda, fukuda@math.ethz.ch
3 Version 0.94h, April 30, 2015
4 Standard ftp site: ftp.ifor.math.ethz.ch, Directory: pub/fukuda/cdd
5*/
6
7/* cdd : C-Implementation of the double description method for
8 computing all vertices and extreme rays of the polyhedron
9 P= {x : b - A x >= 0}.
10 Please read COPYING (GNU General Public Licence) and
11 the manual cddlibman.tex for detail.
12*/
13
14/* This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27*/
28
29/* The first version C0.21 was created on November 10,1993
30 with Dave Gillespie's p2c translator
31 from the Pascal program pdd.p written by Komei Fukuda.
32*/
33
34#include "setoper.h"
35 /* set operation library header (Ver. June 1, 2000 or later) */
36#include "cdd.h"
37#include <stdio.h>
38#include <stdlib.h>
39#include <time.h>
40#include <math.h>
41#include <string.h>
42
43/* Global Variables */
44dd_boolean dd_debug =dd_FALSE;
45dd_boolean dd_log =dd_FALSE;
46/* GLOBAL CONSTANTS and STATICS VARIABLES (to be set by dd_set_global_constants() */
47mytype dd_zero;
48mytype dd_one;
49mytype dd_purezero;
50mytype dd_minuszero;
51mytype dd_minusone;
52
53time_t dd_statStartTime; /* cddlib starting time */
54long dd_statBApivots; /* basis finding pivots */
55long dd_statCCpivots; /* criss-cross pivots */
56long dd_statDS1pivots; /* phase 1 pivots */
57long dd_statDS2pivots; /* phase 2 pivots */
58long dd_statACpivots; /* anticycling (cc) pivots */
59#ifdef GMPRATIONAL
60long dd_statBSpivots; /* basis status checking pivots */
61#endif
62dd_LPSolverType dd_choiceLPSolverDefault; /* Default LP solver Algorithm */
63dd_LPSolverType dd_choiceRedcheckAlgorithm; /* Redundancy Checking Algorithm */
64dd_boolean dd_choiceLexicoPivotQ; /* whether to use the lexicographic pivot */
65
66/* #include <profile.h> THINK C PROFILER */
67/* #include <console.h> THINK C PROFILER */
68
69void dd_DDInit(dd_ConePtr cone)
70{
71 cone->Error=dd_NoError;
72 cone->CompStatus=dd_InProgress;
73 cone->RayCount = 0;
74 cone->TotalRayCount = 0;
75 cone->FeasibleRayCount = 0;
76 cone->WeaklyFeasibleRayCount = 0;
77 cone->EdgeCount=0; /* active edge count */
78 cone->TotalEdgeCount=0; /* active edge count */
79 dd_SetInequalitySets(cone);
80 dd_ComputeRowOrderVector(cone);
81 cone->RecomputeRowOrder=dd_FALSE;
82}
83
84void dd_DDMain(dd_ConePtr cone)
85{
86 dd_rowrange hh, itemp, otemp;
87 dd_boolean locallog=dd_log; /* if dd_log=dd_FALSE, no log will be written. */
88
89 if (cone->d<=0){
90 cone->Iteration=cone->m;
91 cone->FeasibleRayCount=0;
92 cone->CompStatus=dd_AllFound;
93 goto _L99;
94 }
95 if (locallog) {
96 fprintf(stderr,"(Initially added rows ) = ");
97 set_fwrite(stderr,cone->InitialHalfspaces);
98 }
99 while (cone->Iteration <= cone->m) {
100 dd_SelectNextHalfspace(cone, cone->WeaklyAddedHalfspaces, &hh);
101 if (set_member(hh,cone->NonequalitySet)){ /* Skip the row hh */
102 if (dd_debug) {
103 fprintf(stderr,"*The row # %3ld should be inactive and thus skipped.\n", hh);
104 }
105 set_addelem(cone->WeaklyAddedHalfspaces, hh);
106 } else {
107 if (cone->PreOrderedRun)
108 dd_AddNewHalfspace2(cone, hh);
109 else{
110 dd_AddNewHalfspace1(cone, hh);
111 }
112 set_addelem(cone->AddedHalfspaces, hh);
113 set_addelem(cone->WeaklyAddedHalfspaces, hh);
114 }
115 if (!cone->PreOrderedRun){
116 for (itemp=1; cone->OrderVector[itemp]!=hh; itemp++);
117 otemp=cone->OrderVector[cone->Iteration];
118 cone->OrderVector[cone->Iteration]=hh;
119 /* store the dynamic ordering in ordervec */
120 cone->OrderVector[itemp]=otemp;
121 /* store the dynamic ordering in ordervec */
122 }
123 if (locallog){
124 fprintf(stderr,"(Iter, Row, #Total, #Curr, #Feas)= %5ld %5ld %9ld %6ld %6ld\n",
125 cone->Iteration, hh, cone->TotalRayCount, cone->RayCount,
126 cone->FeasibleRayCount);
127 }
128 if (cone->CompStatus==dd_AllFound||cone->CompStatus==dd_RegionEmpty) {
129 set_addelem(cone->AddedHalfspaces, hh);
130 goto _L99;
131 }
132 (cone->Iteration)++;
133 }
134 _L99:;
135 if (cone->d<=0 || cone->newcol[1]==0){ /* fixing the number of output */
136 cone->parent->n=cone->LinearityDim + cone->FeasibleRayCount -1;
137 cone->parent->ldim=cone->LinearityDim - 1;
138 } else {
139 cone->parent->n=cone->LinearityDim + cone->FeasibleRayCount;
140 cone->parent->ldim=cone->LinearityDim;
141 }
142}
143
144
145void dd_InitialDataSetup(dd_ConePtr cone)
146{
147 long j, r;
148 dd_rowset ZSet;
149 static dd_Arow Vector1,Vector2;
150 static dd_colrange last_d=0;
151
152 if (last_d < cone->d){
153 if (last_d>0) {
154 for (j=0; j<last_d; j++){
155 dd_clear(Vector1[j]);
156 dd_clear(Vector2[j]);
157 }
158 free(Vector1); free(Vector2);
159 }
160 Vector1=(mytype*)calloc(cone->d,sizeof(mytype));
161 Vector2=(mytype*)calloc(cone->d,sizeof(mytype));
162 for (j=0; j<cone->d; j++){
163 dd_init(Vector1[j]);
164 dd_init(Vector2[j]);
165 }
166 last_d=cone->d;
167 }
168
169 cone->RecomputeRowOrder=dd_FALSE;
170 cone->ArtificialRay = NULL;
171 cone->FirstRay = NULL;
172 cone->LastRay = NULL;
173 set_initialize(&ZSet,cone->m);
174 dd_AddArtificialRay(cone);
175 set_copy(cone->AddedHalfspaces, cone->InitialHalfspaces);
176 set_copy(cone->WeaklyAddedHalfspaces, cone->InitialHalfspaces);
177 dd_UpdateRowOrderVector(cone, cone->InitialHalfspaces);
178 for (r = 1; r <= cone->d; r++) {
179 for (j = 0; j < cone->d; j++){
180 dd_set(Vector1[j], cone->B[j][r-1]);
181 dd_neg(Vector2[j], cone->B[j][r-1]);
182 }
183 dd_Normalize(cone->d, Vector1);
184 dd_Normalize(cone->d, Vector2);
185 dd_ZeroIndexSet(cone->m, cone->d, cone->A, Vector1, ZSet);
186 if (set_subset(cone->EqualitySet, ZSet)){
187 if (dd_debug) {
188 fprintf(stderr,"add an initial ray with zero set:");
189 set_fwrite(stderr,ZSet);
190 }
191 dd_AddRay(cone, Vector1);
192 if (cone->InitialRayIndex[r]==0) {
193 dd_AddRay(cone, Vector2);
194 if (dd_debug) {
195 fprintf(stderr,"and add its negative also.\n");
196 }
197 }
198 }
199 }
200 dd_CreateInitialEdges(cone);
201 cone->Iteration = cone->d + 1;
202 if (cone->Iteration > cone->m) cone->CompStatus=dd_AllFound; /* 0.94b */
203 set_free(ZSet);
204}
205
206dd_boolean dd_CheckEmptiness(dd_PolyhedraPtr poly, dd_ErrorType *err)
207{
208 dd_rowset R, S;
209 dd_MatrixPtr M=NULL;
210 dd_boolean answer=dd_FALSE;
211
212 *err=dd_NoError;
213
214 if (poly->representation==dd_Inequality){
215 M=dd_CopyInequalities(poly);
216 set_initialize(&R, M->rowsize);
217 set_initialize(&S, M->rowsize);
218 if (!dd_ExistsRestrictedFace(M, R, S, err)){
219 poly->child->CompStatus=dd_AllFound;
220 poly->IsEmpty=dd_TRUE;
221 poly->n=0;
222 answer=dd_TRUE;
223 }
224 set_free(R);
225 set_free(S);
226 dd_FreeMatrix(M);
227 } else if (poly->representation==dd_Generator && poly->m<=0){
228 *err=dd_EmptyVrepresentation;
229 poly->IsEmpty=dd_TRUE;
230 poly->child->CompStatus=dd_AllFound;
231 answer=dd_TRUE;
232 poly->child->Error=*err;
233 }
234
235 return answer;
236}
237
238
239dd_boolean dd_DoubleDescription(dd_PolyhedraPtr poly, dd_ErrorType *err)
240{
241 dd_ConePtr cone=NULL;
242 dd_boolean found=dd_FALSE;
243
244 *err=dd_NoError;
245
246 if (poly!=NULL && (poly->child==NULL || poly->child->CompStatus!=dd_AllFound)){
247 cone=dd_ConeDataLoad(poly);
248 /* create a cone associated with poly by homogenization */
249 time(&cone->starttime);
250 dd_DDInit(cone);
251 if (poly->representation==dd_Generator && poly->m<=0){
252 *err=dd_EmptyVrepresentation;
253 cone->Error=*err;
254 goto _L99;
255 }
256 /* Check emptiness of the polyhedron */
257 dd_CheckEmptiness(poly,err);
258
259 if (cone->CompStatus!=dd_AllFound){
260 dd_FindInitialRays(cone, &found);
261 if (found) {
262 dd_InitialDataSetup(cone);
263 if (cone->CompStatus==dd_AllFound) goto _L99;
264 dd_DDMain(cone);
265 if (cone->FeasibleRayCount!=cone->RayCount) *err=dd_NumericallyInconsistent; /* cddlib-093d */
266 }
267 }
268 time(&cone->endtime);
269 }
270
271_L99: ;
272
273 return found;
274}
275
276dd_boolean dd_DoubleDescription2(dd_PolyhedraPtr poly, dd_RowOrderType horder, dd_ErrorType *err)
277{
278 dd_ConePtr cone=NULL;
279 dd_boolean found=dd_FALSE;
280
281 *err=dd_NoError;
282
283 if (poly!=NULL && (poly->child==NULL || poly->child->CompStatus!=dd_AllFound)){
284 cone=dd_ConeDataLoad(poly);
285 /* create a cone associated with poly by homogenization */
286 cone->HalfspaceOrder=horder; /* set the row order */
287 time(&cone->starttime);
288 dd_DDInit(cone);
289 if (poly->representation==dd_Generator && poly->m<=0){
290 *err=dd_EmptyVrepresentation;
291 cone->Error=*err;
292 goto _L99;
293 }
294 /* Check emptiness of the polyhedron */
295 dd_CheckEmptiness(poly,err);
296
297 if (cone->CompStatus!=dd_AllFound){
298 dd_FindInitialRays(cone, &found);
299 if (found) {
300 dd_InitialDataSetup(cone);
301 if (cone->CompStatus==dd_AllFound) goto _L99;
302 dd_DDMain(cone);
303 if (cone->FeasibleRayCount!=cone->RayCount) *err=dd_NumericallyInconsistent; /* cddlib-093d */
304 }
305 }
306 time(&cone->endtime);
307 }
308
309_L99: ;
310
311 return found;
312}
313
314dd_boolean dd_DDInputAppend(dd_PolyhedraPtr *poly, dd_MatrixPtr M,
315 dd_ErrorType *err)
316{
317 /* This is imcomplete. It simply solves the problem from scratch. */
318 dd_boolean found;
319 dd_ErrorType error;
320
321 if ((*poly)->child!=NULL) dd_FreeDDMemory(*poly);
322 dd_AppendMatrix2Poly(poly, M);
323 (*poly)->representation=dd_Inequality;
324 found=dd_DoubleDescription(*poly, &error);
325 *err=error;
326 return found;
327}
328
329dd_boolean dd_DDFile2File(char *ifile, char *ofile, dd_ErrorType *err)
330{
331 /* The representation conversion from an input file to an outfile. */
332 /* modified by D. Avis to allow stdin/stdout */
333 dd_boolean found=dd_TRUE;
334 FILE *reading=NULL,*writing=NULL;
335 dd_PolyhedraPtr poly;
336 dd_MatrixPtr M, A, G;
337
338 if (strcmp(ifile,"**stdin") == 0 )
339 reading = stdin;
340 else if ( ( reading = fopen(ifile, "r") )!= NULL) {
341 fprintf(stderr,"input file %s is open\n", ifile);
342 }
343 else{
344 fprintf(stderr,"The input file %s not found\n",ifile);
345 found=dd_FALSE;
346 *err=dd_IFileNotFound;
347 goto _L99;
348 }
349
350 if (found){
351 if (strcmp(ofile,"**stdout") == 0 )
352 writing = stdout;
353 else if ( (writing = fopen(ofile, "w") ) != NULL){
354 fprintf(stderr,"output file %s is open\n",ofile);
355 found=dd_TRUE;
356 } else {
357 fprintf(stderr,"The output file %s cannot be opened\n",ofile);
358 found=dd_FALSE;
359 *err=dd_OFileNotOpen;
360 goto _L99;
361 }
362 }
363
364 M=dd_PolyFile2Matrix(reading, err);
365 if (*err!=dd_NoError){
366 goto _L99;
367 } poly=dd_DDMatrix2Poly(M, err); /* compute the second representation */ dd_FreeMatrix(M);
368
369 if (*err==dd_NoError) {
370 dd_WriteRunningMode(writing, poly);
371 A=dd_CopyInequalities(poly);
372 G=dd_CopyGenerators(poly);
373
374 if (poly->representation==dd_Inequality) {
375 dd_WriteMatrix(writing,G);
376 } else {
377 dd_WriteMatrix(writing,A);
378 }
379
380 dd_FreePolyhedra(poly);
381 dd_FreeMatrix(A);
382 dd_FreeMatrix(G);
383 }
384
385_L99: ;
386 if (*err!=dd_NoError) dd_WriteErrorMessages(stderr,*err);
387 if (reading!=NULL) fclose(reading);
388 if (writing!=NULL) fclose(writing);
389 return found;
390}
391
392/* end of cddlib.c */