Austin Schuh | 405fa6c | 2015-09-06 18:13:55 -0700 | [diff] [blame] | 1 | /* 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 */ |
| 44 | dd_boolean dd_debug =dd_FALSE; |
| 45 | dd_boolean dd_log =dd_FALSE; |
| 46 | /* GLOBAL CONSTANTS and STATICS VARIABLES (to be set by dd_set_global_constants() */ |
| 47 | mytype dd_zero; |
| 48 | mytype dd_one; |
| 49 | mytype dd_purezero; |
| 50 | mytype dd_minuszero; |
| 51 | mytype dd_minusone; |
| 52 | |
| 53 | time_t dd_statStartTime; /* cddlib starting time */ |
| 54 | long dd_statBApivots; /* basis finding pivots */ |
| 55 | long dd_statCCpivots; /* criss-cross pivots */ |
| 56 | long dd_statDS1pivots; /* phase 1 pivots */ |
| 57 | long dd_statDS2pivots; /* phase 2 pivots */ |
| 58 | long dd_statACpivots; /* anticycling (cc) pivots */ |
| 59 | #ifdef GMPRATIONAL |
| 60 | long dd_statBSpivots; /* basis status checking pivots */ |
| 61 | #endif |
| 62 | dd_LPSolverType dd_choiceLPSolverDefault; /* Default LP solver Algorithm */ |
| 63 | dd_LPSolverType dd_choiceRedcheckAlgorithm; /* Redundancy Checking Algorithm */ |
| 64 | dd_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 | |
| 69 | void 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 | |
| 84 | void 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 | |
| 145 | void 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 | |
| 206 | dd_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 | |
| 239 | dd_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 | |
| 276 | dd_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 | |
| 314 | dd_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 | |
| 329 | dd_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 */ |