/* lrslib.hpp (vertex enumeration using lexicographic reverse search) */
#define TITLE "lrslib "
#define VERSION "v.6.2 2016.3.28"
#define AUTHOR "*Copyright (C) 1995,2016, David Avis avis@cs.mcgill.ca "
/* This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/
/*Ver 6.1 major change is new lrsnash driver and library coded by Terje Lensberg */
/*Ver 6.0 major change is mplrs wrapper for multithreading coded by Skip Jordan */
/*Ver 5.0 major change is plrs wrapper for multithreading coded by Gary Roumanis */
/*Ver 4.2* library version */
/******************************************************************************/
/* See http://cgm.cs.mcgill.ca/~avis/C/lrs.html for usage instructions */
/******************************************************************************/
#ifdef PLRS
#include <algorithm>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#endif
#ifdef LRSLONG
#define ARITH "lrslong.h" /* lrs long integer arithmetic package */
#else
#ifdef GMP
#define ARITH "lrsgmp.h" /* lrs wrapper for gmp multiple precsion arithmetic */
#else
#define ARITH "lrsmp.h" /* lrs multiple precsion arithmetic */
#define MP
#endif
#endif
#include ARITH
#ifdef SIGNALS
#include <signal.h>
#include <unistd.h>
#define errcheck(s,e) if ((long)(e)==-1L){ perror(s);exit(1);}
#endif
#define CALLOC(n,s) xcalloc(n,s,__LINE__,__FILE__)
/*********************/
/*global constants */
/*********************/
#define MAX_LRS_GLOBALS 10000L /* number of allocated dictionaries */
#define MAXIMIZE 1L /* maximize the lp */
#define MINIMIZE 0L /* maximize the lp */
#define GE 1L /* constraint is >= */
#define EQ 0L /* constraint is linearity */
/*************/
/* typedefs */
/*************/
/******************************************************************************/
/* Indexing after initialization */
/* Basis Cobasis */
/* --------------------------------------- ----------------------------- */
/* | i |0|1| .... |lastdv|lastdv+1|...|m| | j | 0 | 1 | ... |d-1| d | */
/* |-----|+|+|++++++|++++++|--------|---|-| |----|---|---|-----|---|+++++| */
/* |B[i] |0|1| .... |lastdv|lastdv+1|...|m| |C[j]|m+1|m+2| ... |m+d|m+d+1| */
/* -----|+|+|++++++|++++++|????????|???|?| ----|???|???|-----|???|+++++| */
/* */
/* Row[i] is row location for B[i] Col[j] is column location for C[j] */
/* ----------------------------- ----------------------------- */
/* | i |0|1| ..........|m-1|m| | j | 0 | 1 | ... |d-1| d | */
/* |-------|+|-|-----------|---|-| |------|---|---|--- |---|++++| */
/* |Row[i] |0|1|...........|m-1|m| |Col[j]| 1 | 2 | ... | d | 0 | */
/* --------|+|*|***********|***|*| ------|***|***|*****|***|++++| */
/* */
/* + = remains invariant * = indices may be permuted ? = swapped by pivot */
/* */
/* m = number of input rows n= number of input columns */
/* input dimension inputd = n-1 (H-rep) or n (V-rep) */
/* lastdv = inputd-nredundcol (each redundant column removes a dec. var) */
/* working dimension d=lastdv-nlinearity (an input linearity removes a slack) */
/* obj function in row 0, index 0=B[0] col 0 has index m+d+1=C[d] */
/* H-rep: b-vector in col 0, A matrix in columns 1..n-1 */
/* V-rep: col 0 all zero, b-vector in col 1, A matrix in columns 1..n */
/******************************************************************************/
typedef struct lrs_dic_struct /* dynamic dictionary data */
{
lrs_mp_matrix A;
long m; /* A has m+1 rows, row 0 is cost row */
long m_A; /* =m or m-d if nonnegative flag set */
long d; /* A has d+1 columns, col 0 is b-vector */
long d_orig; /* value of d as A was allocated (E.G.) */
long lexflag; /* true if lexmin basis for this vertex */
long depth; /* depth of basis/vertex in reverse search tree */
long i, j; /* last pivot row and column pivot indices */
lrs_mp det; /* current determinant of basis */
lrs_mp objnum; /* objective numerator value */
lrs_mp objden; /* objective denominator value */
long *B, *Row; /* basis, row location indices */
long *C, *Col; /* cobasis, column location indices */
struct lrs_dic_struct *prev, *next;
} lrs_dic;
typedef struct lrs_dat /* global problem data */
{
lrs_mp_vector Gcd; /* Gcd of each row of numerators */
lrs_mp_vector Lcm; /* Lcm for each row of input denominators */
lrs_mp sumdet; /* sum of determinants */
lrs_mp Nvolume; /* volume numerator */
lrs_mp Dvolume; /* volume denominator */
lrs_mp boundn; /* objective bound numerator */
lrs_mp boundd; /* objective bound denominator */
long unbounded; /* lp unbounded */
char fname[100]; /* input file name from line 1 of input */
long *inequality; /* indices of inequalities corr. to cobasic ind */
/* initially holds order used to find starting */
/* basis, default: m,m-1,...,2,1 */
long *facet; /* cobasic indices for restart in needed */
long *redundcol; /* holds columns which are redundant */
long *linearity; /* holds cobasic indices of input linearities */
long *minratio; /* used for lexicographic ratio test */
long *temparray; /* for sorting indices, dimensioned to d */
long *isave, *jsave; /* arrays for estimator, malloc'ed at start */
long inputd; /* input dimension: n-1 for H-rep, n for V-rep */
long m; /* number of rows in input file */
long n; /* number of columns in input file */
long lastdv; /* index of last dec. variable after preproc */
/* given by inputd-nredundcol */
long count[10]; /* count[0]=rays [1]=verts. [2]=base [3]=pivots */
/* count[4]=integer vertices */
long startcount[5];
long deepest; /* max depth ever reached in search */
long nredundcol; /* number of redundant columns */
long nlinearity; /* number of input linearities */
long totalnodes; /* count total number of tree nodes evaluated */
long runs; /* probes for estimate function */
long seed; /* seed for random number generator */
double cest[10]; /* ests: 0=rays,1=vert,2=bases,3=vol,4=int vert */
/**** flags ********** */
long allbases; /* TRUE if all bases should be printed */
long bound; /* TRUE if upper/lower bound on objective given */
long countonly; /* TRUE if only count totals should be output */
long debug;
long dualdeg; /* TRUE if start dictionary is dual degenerate */
long etrace; /* turn off debug at basis # strace */
long frequency; /* frequency to print cobasis indices */
long geometric; /* TRUE if incident vertex prints after each ray */
long getvolume; /* do volume calculation */
long givenstart; /* TRUE if a starting cobasis is given */
long homogeneous; /* TRUE if all entries in column one are zero */
long hull; /* do convex hull computation if TRUE */
long incidence; /* print all tight inequalities (vertices/rays) */
long lponly; /* true if only lp solution wanted */
long maxdepth; /* max depth to search to in treee */
long maximize; /* flag for LP maximization */
long maxoutput; /* if positive, maximum number of output lines */
long maxcobases; /* if positive, after maxcobasis unexplored subtrees reported */
long minimize; /* flag for LP minimization */
long mindepth; /* do not backtrack above mindepth */
long nash; /* TRUE for computing nash equilibria */
long nonnegative; /* TRUE if last d constraints are nonnegativity */
long polytope; /* TRUE for facet computation of a polytope */
long printcobasis; /* TRUE if all cobasis should be printed */
long printslack; /* TRUE if indices of slack inequal. printed */
long truncate; /* TRUE: truncate tree when moving from opt vert*/
long verbose; /* FALSE for minimalist output */
long restart; /* TRUE if restarting from some cobasis */
long strace; /* turn on debug at basis # strace */
long voronoi; /* compute voronoi vertices by transformation */
long subtreesize; /* in estimate mode, iterates if cob_est >= subtreesize */
/* Variables for saving/restoring cobasis, db */
long id; /* numbered sequentially */
char *name; /* passed by user */
long saved_count[3]; /* How often to print out current cobasis */
long *saved_C;
lrs_mp saved_det;
long saved_depth;
long saved_d;
long saved_flag; /* There is something in the saved cobasis */
/* Variables for cacheing dictionaries, db */
lrs_dic *Qhead, *Qtail;
}lrs_dat, lrs_dat_p;
#ifdef PLRS
/****************/
/* PLRS */
/****************/
void post_output(const char *, const char *);
void plrs_read_dat (lrs_dat * Q, std::ifstream &ff);
void plrs_read_dic (lrs_dic * P, lrs_dat * Q, std::ifstream &ff);
void plrs_readfacets (lrs_dat * Q, long facet[], string facets);
void plrs_readlinearity(lrs_dat *Q, string line);
#endif
/*******************************/
/* functions for external use */
/*******************************/
extern FILE *lrs_cfp; /* output file for checkpoint information */
long lrs_main (int argc, char *argv[]); /* lrs driver, argv[1]=input file, [argc-1]=output file */
long redund_main (int argc, char *argv[]); /* redund driver, argv[1]=input file, [2]=output file */
lrs_dat *lrs_alloc_dat (const char *name); /* allocate for lrs_dat structure "name" */
lrs_dic *lrs_alloc_dic (lrs_dat * Q); /* allocate for lrs_dic structure corr. to Q */
long lrs_estimate (lrs_dic * P, lrs_dat * Q); /* get estimates only and returns est number of cobases in subtree */
long lrs_read_dat (lrs_dat * Q, int argc, char *argv[]); /* read header and set up lrs_dat */
long lrs_read_dic (lrs_dic * P, lrs_dat * Q); /* read input and set up problem and lrs_dic */
long lrs_checkbound (lrs_dic *P, lrs_dat * Q); /* TRUE if current objective value exceeds specified bound */
long lrs_getfirstbasis (lrs_dic ** P_p, lrs_dat * Q, lrs_mp_matrix * Lin,long no_output); /* gets first basis, FALSE if none,P may get changed if lin. space Lin found no_output is TRUE supresses output headers P may get changed if lin. space Lin found */
void lrs_getinput(lrs_dic *P,lrs_dat *Q,long *num,long *den, long m, long d); /* reads input matrix b A in lrs/cdd format */
long lrs_getnextbasis (lrs_dic ** dict_p, lrs_dat * Q, long prune); /* gets next lrs tree basis, FALSE if none backtrack if prune is TRUE */
long lrs_getsolution (lrs_dic * P, lrs_dat * Q, lrs_mp_vector output, long col);
long lrs_getray (lrs_dic * P, lrs_dat * Q, long col, long comment, lrs_mp_vector output);
long lrs_getvertex (lrs_dic * P, lrs_dat * Q, lrs_mp_vector output);
void lrs_close (char *name); /* close lrs lib program "name" */
long lrs_init (char *name); /* initialize lrslib and arithmetic package for prog "name" */
void lrs_lpoutput(lrs_dic * P,lrs_dat * Q, lrs_mp_vector output); /* print LP primal and dual solutions */
void lrs_printcobasis (lrs_dic * P, lrs_dat * Q, long col); /* print cobasis for column col(verted or ray) */
void lrs_printoutput (lrs_dat * Q, lrs_mp_vector output); /* print output array */
void lrs_printrow (char name[], lrs_dat * Q, lrs_mp_vector output, long rowd); /*print row of A matrix in output[0..rowd] */
void lrs_printsol (lrs_dic * P, lrs_dat * Q, long col, long comment); /* print out solution from col, comment= 0=normal,-1=geometric ray,1..inputd=linearity */
void lrs_printtotals (lrs_dic * P, lrs_dat * Q);/* print final totals for lrs */
long lrs_set_digits (long dec_digits ); /* set lrsmp digits to equiv. of decimal dec_digits */
long lrs_solvelp (lrs_dic * P, lrs_dat * Q, long maximize);/* solve primal feas LP:TRUE bounded else FALSE */
/*******************************/
/* functions for internal use */
/*******************************/
/*******************************/
/* basic dictionary functions */
/*******************************/
long getabasis (lrs_dic * P, lrs_dat * Q, long order[]); /* Try to find a starting basis */
void getnextoutput (lrs_dic * P, lrs_dat * Q, long i, long col, lrs_mp out); /* get A[B[i][col] and copy to out */
long ismin (lrs_dic * P, lrs_dat * Q, long r, long s); /* test if A[r][s] is a min ratio for col s */
long lexmin (lrs_dic * P, lrs_dat * Q, long col); /* test A to see if current basis is lexmin */
void pivot (lrs_dic * P, lrs_dat * Q, long bas, long cob); /* Qpivot routine for array A */
long primalfeasible (lrs_dic * P, lrs_dat * Q); /* Do dual pivots to get primal feasibility */
long lrs_ratio (lrs_dic * P, lrs_dat * Q, long col); /* find lex min. ratio */
long removecobasicindex (lrs_dic * P, lrs_dat * Q, long k); /* remove C[k] from problem */
long restartpivots (lrs_dic * P, lrs_dat * Q); /* restart problem from given cobasis */
long reverse (lrs_dic * P, lrs_dat * Q, long *r, long s); /* TRUE if B[*r] C[s] is a reverse lex-pos pivot */
long selectpivot (lrs_dic * P, lrs_dat * Q, long *r, long *s); /* select pivot indices using lexicographic rule */
long dan_selectpivot (lrs_dic * P, lrs_dat * Q, long *r, long *s); /* select pivot indices using dantzig-lex rule */
void update (lrs_dic * P, lrs_dat * Q, long *i, long *j); /* update the B,C, LOC arrays after a pivot */
void updatevolume (lrs_dic * P, lrs_dat * Q); /* rescale determinant and update the volume */
/*******************************/
/* other functions using P,Q */
/*******************************/
long lrs_degenerate (lrs_dic * P, lrs_dat * Q); /* TRUE if the dictionary is primal degenerate */
void print_basis (FILE * fp, lrs_dat * Q);
void printA (lrs_dic * P, lrs_dat * Q); /* raw print of dictionary, bases for debugging */
void pimat (lrs_dic * P, long r, long s, lrs_mp Nt, char name[]); /* print the row r col s of A */
long readfacets (lrs_dat * Q, long facet[]); /* read and check facet list */
long readlinearity (lrs_dat * Q); /* read and check linearity list */
void rescaledet (lrs_dic * P, lrs_dat * Q, lrs_mp Vnum, lrs_mp Vden); /* rescale determinant to get its volume */
void rescalevolume (lrs_dic * P, lrs_dat * Q, lrs_mp Vnum, lrs_mp Vden); /* adjust volume for dimension */
long lrs_leaf(lrs_dic *P, lrs_dat *Q); /* true if current dictionary is leaf of reverse search tree */
/***************************************************/
/* Routines for redundancy checking */
/***************************************************/
long checkredund (lrs_dic * P, lrs_dat * Q);/* solve primal lp to check redund of obj fun. returns TRUE if redundant, else FALSE */
long checkcobasic (lrs_dic * P, lrs_dat * Q, long index); /* TRUE if index is cobasic and nondegenerate FALSE if basic, or degen. cobasic, where it will get pivoted out */
long checkindex (lrs_dic * P, lrs_dat * Q, long index); /* index=0 non-red.,1 red., 2 input linearity NOTE: row is returned all zero if redundant!! */
/***************************************************/
/* Routines for caching and restoring dictionaries */
/***************************************************/
void lrs_free_dic ( lrs_dic *P, lrs_dat *Q);
void lrs_free_dic2 ( lrs_dic *P, lrs_dat *Q); /* same as lrs_free_dic but no cache*/
void lrs_free_dat ( lrs_dat *Q);
void copy_dict (lrs_dat * global, lrs_dic * dest, lrs_dic * src);
lrs_dic *alloc_memory (lrs_dat * Q);
lrs_dic * lrs_getdic(lrs_dat *Q);
lrs_dic *resize (lrs_dic * P, lrs_dat * Q);
/*******************************/
/* utilities */
/*******************************/
void lprat (const char *name, long Num, long Den); /* Print Num/Den without reducing */
long lreadrat (long *Num, long *Den); /* read a rational string and convert to long integers */
void reorder (long a[], long range); /* reorder array in increasing order with one misplaced element */
void reorder1 (long a[], long b[], long newone, long range); /* reorder array a in increasing order with misplaced element newone elements of b go along for the ride */
/***************************/
/* lp_solve like functions */
/***************************/
long lrs_solve_lp(lrs_dic *P, lrs_dat *Q);/* solve lp only for given dictionary */
void lrs_set_row(lrs_dic *P, lrs_dat *Q, long row, long num[], long den[], long ineq);/* load row i of dictionary from num[]/den[] ineq=GE */
void lrs_set_row_mp(lrs_dic *P, lrs_dat *Q, long row, lrs_mp_vector num, lrs_mp_vector den, long ineq);/* same as lrs_set_row except num/den is lrs_mp type */
void lrs_set_obj(lrs_dic *P, lrs_dat *Q, long num[], long den[], long max); /* set up objective function with coeffs num[]/den[] max=MAXIMIZE or MINIMIZE */
void lrs_set_obj_mp(lrs_dic *P, lrs_dat *Q, lrs_mp_vector num, lrs_mp_vector den, long max);/* same as lrs_set_obj but num/den has lrs_mp type */