// // $Source: /cvsroot/gambit/gambit/sources/tools/enummixed/lrsnash.cc,v $ // $Date: 2006/11/13 06:16:24 $ // $Revision: 1.3 $ // // DESCRIPTION: // Compute Nash equilibria via enumerating extreme points, lrslib version // // This file is part of Gambit // Copyright (c) 2006, The Gambit Project // Based on the implementation in lrslib 4.2b, which is // Copyright (c) 1995-2005, David Avis // // 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // // This file is based heavily on nash.c distributed with lrslib 4.2b. // I have tried where possible to maintain as much of the original, and // make a minimal set of changes to interface with Gambit's game // representation library. This way, hopefully, if future versions of lrslib // fix bugs or create enhancements that are relevant, it will be fairly // easy to port them to this program. -- TLT, 23.viii.2006 // #include #include #include // The order of these next includes is important, because of macro definitions #include "libgambit/libgambit.h" using namespace Gambit; extern "C" { #include "lrslib.h" } //========================================================================== // Building the problem representations //========================================================================== // // These two functions are based upon the program setupnash.c from the // lrslib distribution, and the user's guide documentation. // There are two separate functions, one for each player's problem. // According to the user's guide, the ordering of the constraint rows // is significant, and differs between the players; for player 1's problem // the nonnegativity constraints come first, whereas for player 2's problem // they appear later. Experiments suggest this is in fact true, and // reversing them breaks something. // void FillNonnegativityRows(lrs_dic *P, lrs_dat *Q, int firstRow, int lastRow, int n) { const int MAXCOL = 1000; /* maximum number of columns */ long num[MAXCOL], den[MAXCOL]; for (long row = firstRow; row <= lastRow; row++) { num[0] = 0; den[0] = 1; for (long col = 1; col < n; col++) { num[col] = (row-firstRow+1 == col) ? 1 : 0; den[col] = 1; } lrs_set_row(P, Q, row, num, den, GE); } } void FillConstraintRows(lrs_dic *P, lrs_dat *Q, const StrategySupport &p_support, int p1, int p2, int firstRow) { const int MAXCOL = 1000; /* maximum number of columns */ long num[MAXCOL], den[MAXCOL]; Game game = p_support.GetGame(); Rational min = game->GetMinPayoff() - Rational(1); PureStrategyProfile cont(game); for (long row = firstRow; row < firstRow + p_support.NumStrategies(p1); row++) { num[0] = 0; den[0] = 1; cont.SetStrategy(p_support.GetStrategy(p1, row - firstRow + 1)); for (long st = 1; st <= p_support.NumStrategies(p2); st++) { cont.SetStrategy(p_support.GetStrategy(p2, st)); Rational x = cont.GetPayoff(p1) - min; num[st] = -x.numerator().as_long(); den[st] = x.denominator().as_long(); } num[p_support.NumStrategies(p2)+1] = 1; den[p_support.NumStrategies(p2)+1] = 1; lrs_set_row(P, Q, row, num, den, GE); } } void FillLinearityRow(lrs_dic *P, lrs_dat *Q, int m, int n) { const int MAXCOL = 1000; /* maximum number of columns */ long num[MAXCOL], den[MAXCOL]; num[0] = -1; den[0] = 1; for (int i = 1; i < n-1; i++) { num[i] = 1; den[i] = 1; } num[n-1] = 0; den[n-1] = 1; lrs_set_row(P, Q, m, num, den, EQ); } // // Build the H-representation for player p1 // void BuildRep(lrs_dic *P, lrs_dat *Q, const StrategySupport &p_support, int p1, int p2) { long m=Q->m; /* number of inequalities */ long n=Q->n; if (p1 == 1) { FillConstraintRows(P, Q, p_support, p1, p2, 1); FillNonnegativityRows(P, Q, p_support.NumStrategies(p1) + 1, p_support.MixedProfileLength(), n); } else { FillNonnegativityRows(P, Q, 1, p_support.NumStrategies(p2), n); FillConstraintRows(P, Q, p_support, p1, p2, p_support.NumStrategies(p2) + 1); } FillLinearityRow(P, Q, m, n); } //======================================================================== // Forward declarations of useful functions //======================================================================== /* lrs driver, argv[2]= 2nd input file for nash equilibria */ long nash2_main (lrs_dic *P1, lrs_dat *Q1, lrs_dic *P2orig, lrs_dat *Q2, long *numequilib, lrs_mp_vector output1, lrs_mp_vector output2, const StrategySupport &p_support); long lrs_getfirstbasis2 (lrs_dic ** D_p, lrs_dat * Q, lrs_dic *P2orig, lrs_mp_matrix * Lin, long no_output); long getabasis2 (lrs_dic * P, lrs_dat * Q, lrs_dic * P2orig, long order[]); // This is a modified version of lrs_output from the original, in which // we output the equilibria found in Gambit format. void nashoutput(lrs_dat *Q1, lrs_mp_vector output1, lrs_dat *Q2, lrs_mp_vector output2, const StrategySupport &p_support); // // This is the main function, based on main() from lrslib's 'nash' driver. // void LrsSolve(const StrategySupport &p_support) { lrs_dic *P1,*P2; /* structure for holding current dictionary and indices */ lrs_dat *Q1,*Q2; /* structure for holding static problem data */ lrs_mp_vector output1; /* holds one line of output; ray,vertex,facet,linearity */ lrs_mp_vector output2; /* holds one line of output; ray,vertex,facet,linearity */ lrs_mp_matrix Lin; /* holds input linearities if any are found */ lrs_dic *P2orig; /* we will save player 2's dictionary in getabasis */ long col; /* output column index for dictionary */ long startcol = 0; long prune = FALSE; /* if TRUE, getnextbasis will prune tree and backtrack */ long numequilib=0; /* number of nash equilibria found */ long oldnum=0; /* global variables lrs_ifp and lrs_ofp are file pointers for input and output */ /* they default to stdin and stdout, but may be overidden by command line parms. */ /*************************************************** Step 0: Do some global initialization that should only be done once, no matter how many lrs_dat records are allocated. db ***************************************************/ if (!lrs_init("")) { return; } /*********************************************************************************/ /* Step 1: Allocate lrs_dat, lrs_dic and set up the problem */ /*********************************************************************************/ Q1 = lrs_alloc_dat ("LRS globals"); /* allocate and init structure for static problem data */ if (Q1 == NULL) { return; } Q1->nash=TRUE; Q1->n = p_support.NumStrategies(1) + 2; Q1->m = p_support.MixedProfileLength() + 1; P1 = lrs_alloc_dic (Q1); /* allocate and initialize lrs_dic */ if (P1 == NULL) { return; } BuildRep(P1, Q1, p_support, 2, 1); output1 = lrs_alloc_mp_vector (Q1->n + Q1->m); /* output holds one line of output from dictionary */ /* allocate and init structure for player 2's problem data */ Q2 = lrs_alloc_dat ("LRS globals"); if (Q2 == NULL) { return; } Q2->nash=TRUE; Q2->n = p_support.NumStrategies(2) + 2; Q2->m = p_support.MixedProfileLength() + 1; P2 = lrs_alloc_dic (Q2); /* allocate and initialize lrs_dic */ if (P2 == NULL) { return; } BuildRep(P2, Q2, p_support, 1, 2); output2 = lrs_alloc_mp_vector (Q2->n + Q2->m); /* output holds one line of output from dictionary */ P2orig = lrs_getdic(Q2); /* allocate and initialize lrs_dic */ if (P2orig == NULL) return; copy_dict(Q2,P2orig,P2); /*********************************************************************************/ /* Step 2: Find a starting cobasis from default of specified order */ /* P1 is created to hold active dictionary data and may be cached */ /* Lin is created if necessary to hold linearity space */ /* Print linearity space if any, and retrieve output from first dict. */ /*********************************************************************************/ if (!lrs_getfirstbasis (&P1, Q1, &Lin, TRUE)) return; if (Q1->dualdeg) { printf("\n*Warning! Dual degenerate, ouput may be incomplete"); printf("\n*Recommendation: Add dualperturb option before maximize in first input file\n"); } if (Q1->unbounded) { printf("\n*Warning! Unbounded starting dictionary for p1, output may be incomplete"); printf("\n*Recommendation: Change/remove maximize option, or include bounds \n"); } /* Pivot to a starting dictionary */ /* There may have been column redundancy */ /* If so the linearity space is obtained and redundant */ /* columns are removed. User can access linearity space */ /* from lrs_mp_matrix Lin dimensions nredundcol x d+1 */ if (Q1->homogeneous && Q1->hull) startcol++; /* col zero not treated as redundant */ for (col = startcol; col < Q1->nredundcol; col++) /* print linearity space */ lrs_printoutput (Q1, Lin[col]); /* Array Lin[][] holds the coeffs. */ /*********************************************************************************/ /* Step 3: Terminate if lponly option set, otherwise initiate a reverse */ /* search from the starting dictionary. Get output for each new dict. */ /*********************************************************************************/ /* We initiate reverse search from this dictionary */ /* getting new dictionaries until the search is complete */ /* User can access each output line from output which is */ /* vertex/ray/facet from the lrs_mp_vector output */ /* prune is TRUE if tree should be pruned at current node */ do { prune=lrs_checkbound(P1,Q1); if (!prune && lrs_getsolution (P1, Q1, output1, col)) { oldnum=numequilib; nash2_main(P1,Q1,P2orig,Q2,&numequilib,output1,output2,p_support); if (numequilib > oldnum || Q1->verbose) { if(Q1->verbose) prat(" \np2's obj value: ",P1->objnum,P1->objden); //fprintf (lrs_ofp, "\n"); } } } while (lrs_getnextbasis (&P1, Q1, prune)); lrs_clear_mp_vector(output1, Q1->m + Q1->n); lrs_clear_mp_vector(output2, Q2->m + Q2->n); Q2->Qhead = P2; /* reset this or you crash free_dic */ lrs_free_dic (P2,Q2); /* deallocate lrs_dic */ lrs_free_dat (Q2); /* deallocate lrs_dat */ lrs_free_dic (P1,Q1); /* deallocate lrs_dic */ lrs_free_dat (Q1); /* deallocate lrs_dat */ lrs_close (""); fclose(lrs_ofp); } /*********************************************/ /* end of nash driver */ /*********************************************/ /**********************************************************/ /* nash2_main is a second driver used in computing nash */ /* equilibria on a second polytope interleaved with first */ /**********************************************************/ long nash2_main (lrs_dic *P1, lrs_dat *Q1, lrs_dic *P2orig, lrs_dat *Q2, long *numequilib, lrs_mp_vector output1, lrs_mp_vector output2, const StrategySupport &p_support) { lrs_dic *P2; /* This can get resized, cached etc. Loaded from P2orig */ lrs_mp_matrix Lin; /* holds input linearities if any are found */ long col; /* output column index for dictionary */ long startcol = 0; long prune = FALSE; /* if TRUE, getnextbasis will prune tree and backtrack */ long nlinearity; long *linearity; static long firstwarning=TRUE; /* FALSE if dual deg warning for Q2 already given */ static long firstunbounded=TRUE; /* FALSE if dual deg warning for Q2 already given */ long i,j; /* global variables lrs_ifp and lrs_ofp are file pointers for input and output */ /* they default to stdin and stdout, but may be overidden by command line parms. */ /*********************************************************************************/ /* Step 1: Allocate lrs_dat, lrs_dic and set up the problem */ /*********************************************************************************/ P2=lrs_getdic(Q2); copy_dict(Q2,P2,P2orig); /* Here we take the linearities generated by the current vertex of player 1*/ /* and append them to the linearity in player 2's input matrix */ /* next is the key magic linking player 1 and 2 */ /* be careful if you mess with this! */ linearity=Q2->linearity; nlinearity=0; for(i=Q1->lastdv+1;i <= P1->m; i++) { if (!zero(P1->A[P1->Row[i]][0])) { j = Q1->inequality[P1->B[i]-Q1->lastdv]; if (j < Q1->linearity[0]) linearity[nlinearity++]= j; } } /* add back in the linearity for probs summing to one */ linearity[nlinearity++]= Q1->linearity[0]; /*sort linearities */ for (i = 1; i < nlinearity; i++) reorder (linearity, nlinearity); if(Q2->verbose) { fprintf(lrs_ofp,"\np2: linearities %ld",nlinearity); for (i=0;i < nlinearity; i++) fprintf(lrs_ofp," %ld",linearity[i]); } Q2->nlinearity = nlinearity; Q2->polytope = FALSE; /*********************************************************************************/ /* Step 2: Find a starting cobasis from default of specified order */ /* P2 is created to hold active dictionary data and may be cached */ /* Lin is created if necessary to hold linearity space */ /* Print linearity space if any, and retrieve output from first dict. */ /*********************************************************************************/ if (!lrs_getfirstbasis2 (&P2, Q2, P2orig, &Lin, TRUE)) goto sayonara; if (firstwarning && Q2->dualdeg) { firstwarning=FALSE; printf("\n*Warning! Dual degenerate, ouput may be incomplete"); printf("\n*Recommendation: Add dualperturb option before maximize in second input file\n"); } if (firstunbounded && Q2->unbounded) { firstunbounded=FALSE; printf("\n*Warning! Unbounded starting dictionary for p2, output may be incomplete"); printf("\n*Recommendation: Change/remove maximize option, or include bounds \n"); } /* Pivot to a starting dictionary */ /* There may have been column redundancy */ /* If so the linearity space is obtained and redundant */ /* columns are removed. User can access linearity space */ /* from lrs_mp_matrix Lin dimensions nredundcol x d+1 */ if (Q2->homogeneous && Q2->hull) startcol++; /* col zero not treated as redundant */ /* for (col = startcol; col < Q2->nredundcol; col++)*/ /* print linearity space */ /*lrs_printoutput (Q2, Lin[col]);*/ /* Array Lin[][] holds the coeffs. */ /*********************************************************************************/ /* Step 3: Terminate if lponly option set, otherwise initiate a reverse */ /* search from the starting dictionary. Get output for each new dict. */ /*********************************************************************************/ /* We initiate reverse search from this dictionary */ /* getting new dictionaries until the search is complete */ /* User can access each output line from output which is */ /* vertex/ray/facet from the lrs_mp_vector output */ /* prune is TRUE if tree should be pruned at current node */ do { prune=lrs_checkbound(P2,Q2); col=0; if (!prune && lrs_getsolution (P2, Q2, output2, col)) { (*numequilib)++; if (Q2->verbose) prat(" \np1's obj value: ",P2->objnum,P2->objden); nashoutput(Q1, output1, Q2, output2, p_support); } } while (lrs_getnextbasis (&P2, Q2, prune)); sayonara: lrs_free_dic(P2,Q2); return 0; } /*********************************************/ /* end of nash2_main */ /*********************************************/ /* In lrs_getfirstbasis and lrs_getnextbasis we use D instead of P */ /* since the dictionary P may change, ie. &P in calling routine */ #define D (*D_p) long lrs_getfirstbasis2 (lrs_dic ** D_p, lrs_dat * Q, lrs_dic * P2orig, 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 */ { long i, j, k; /* assign local variables to structures */ lrs_mp_matrix A; long *B, *C, *Row, *Col; long *inequality; long *linearity; long hull = Q->hull; long m, d, lastdv, nlinearity, nredundcol; static long ocount=0; m = D->m; d = D->d; lastdv = Q->lastdv; nredundcol = 0L; /* will be set after getabasis */ nlinearity = Q->nlinearity; /* may be reset if new linearity read */ linearity = Q->linearity; A = D->A; B = D->B; C = D->C; Row = D->Row; Col = D->Col; inequality = Q->inequality; /* default is to look for starting cobasis using linearies first, then */ /* filling in from last rows of input as necessary */ /* linearity array is assumed sorted here */ /* note if restart/given start inequality indices already in place */ /* from nlinearity..d-1 */ for (i = 0; i < nlinearity; i++) /* put linearities first in the order */ inequality[i] = linearity[i]; k = 0; /* index for linearity array */ if (Q->givenstart) k = d; else k = nlinearity; for (i = m; i >= 1; i--) { j = 0; while (j < k && inequality[j] != i) j++; /* see if i is in inequality */ if (j == k) inequality[k++] = i; } if (Q->debug) { fprintf (lrs_ofp, "\n*Starting cobasis uses input row order"); for (i = 0; i < m; i++) fprintf (lrs_ofp, " %ld", inequality[i]); } if (!Q->maximize && !Q->minimize) for (j = 0; j <= d; j++) itomp (ZERO, A[0][j]); /* Now we pivot to standard form, and then find a primal feasible basis */ /* Note these steps MUST be done, even if restarting, in order to get */ /* the same index/inequality correspondance we had for the original prob. */ /* The inequality array is used to give the insertion order */ /* and is defaulted to the last d rows when givenstart=FALSE */ if (!getabasis2 (D, Q,P2orig, inequality)) return FALSE; if(Q->debug) { fprintf(lrs_ofp,"\nafter getabasis2"); printA(D, Q); } nredundcol = Q->nredundcol; lastdv = Q->lastdv; d = D->d; /********************************************************************/ /* now we start printing the output file unless no output requested */ /********************************************************************/ if (!no_output || Q->debug) { fprintf (lrs_ofp, "\nV-representation"); /* Print linearity space */ /* Don't print linearity if first column zero in hull computation */ k = 0; if (nredundcol > k) { fprintf (lrs_ofp, "\nlinearity %ld ", nredundcol - k); /*adjust nredundcol for homog. */ for (i = 1; i <= nredundcol - k; i++) fprintf (lrs_ofp, " %ld", i); } /* end print of linearity space */ fprintf (lrs_ofp, "\nbegin"); fprintf (lrs_ofp, "\n***** %ld rational", Q->n); } /* end of if !no_output ....... */ /* Reset up the inequality array to remember which index is which input inequality */ /* inequality[B[i]-lastdv] is row number of the inequality with index B[i] */ /* inequality[C[i]-lastdv] is row number of the inequality with index C[i] */ for (i = 1; i <= m; i++) inequality[i] = i; if (nlinearity > 0) /* some cobasic indices will be removed */ { for (i = 0; i < nlinearity; i++) /* remove input linearity indices */ inequality[linearity[i]] = 0; k = 1; /* counter for linearities */ for (i = 1; i <= m - nlinearity; i++) { while (k <= m && inequality[k] == 0) k++; /* skip zeroes in corr. to linearity */ inequality[i] = inequality[k++]; } } /* end if linearity */ if (Q->debug) { fprintf (lrs_ofp, "\ninequality array initialization:"); for (i = 1; i <= m - nlinearity; i++) fprintf (lrs_ofp, " %ld", inequality[i]); } if (nredundcol > 0) { *Lin = lrs_alloc_mp_matrix (nredundcol, Q->n); for (i = 0; i < nredundcol; i++) { if (!(Q->homogeneous && Q->hull && i == 0)) /* skip redund col 1 for homog. hull */ { lrs_getray (D, Q, Col[0], D->C[0] + i - hull, (*Lin)[i]); /* adjust index for deletions */ } if (!removecobasicindex (D, Q, 0L)) return FALSE; } } /* end if nredundcol > 0 */ if (Q->verbose) { fprintf (lrs_ofp, "\nNumber of pivots for starting dictionary: %ld",Q->count[3]); ocount=Q->count[3]; } /* Do dual pivots to get primal feasibility */ if (!primalfeasible (D, Q)) { if ( Q->verbose ) { fprintf (lrs_ofp, "\nNumber of pivots for feasible solution: %ld",Q->count[3]); fprintf (lrs_ofp, " - No feasible solution"); ocount=Q->count[3]; } return FALSE; } if (Q->verbose) { fprintf (lrs_ofp, "\nNumber of pivots for feasible solution: %ld",Q->count[3]); ocount=Q->count[3]; } /* Now solve LP if objective function was given */ if (Q->maximize || Q->minimize) { Q->unbounded = !lrs_solvelp (D, Q, Q->maximize); /* check to see if objective is dual degenerate */ j = 1; while (j <= d && !zero (A[0][j])) j++; if (j <= d) Q->dualdeg = TRUE; } else /* re-initialize cost row to -det */ { for (j = 1; j <= d; j++) { copy (A[0][j], D->det); storesign (A[0][j], NEG); } itomp (ZERO, A[0][0]); /* zero optimum objective value */ } /* reindex basis to 0..m if necessary */ /* we use the fact that cobases are sorted by index value */ if (Q->debug) printA (D, Q); while (C[0] <= m) { i = C[0]; j = inequality[B[i] - lastdv]; inequality[B[i] - lastdv] = inequality[C[0] - lastdv]; inequality[C[0] - lastdv] = j; C[0] = B[i]; B[i] = i; reorder1 (C, Col, ZERO, d); } if (Q->debug) { fprintf (lrs_ofp, "\n*Inequality numbers for indices %ld .. %ld : ", lastdv + 1, m + d); for (i = 1; i <= m - nlinearity; i++) fprintf (lrs_ofp, " %ld ", inequality[i]); printA (D, Q); } if (Q->restart) { if (Q->debug) fprintf (lrs_ofp, "\nPivoting to restart co-basis"); if (!restartpivots (D, Q)) return FALSE; D->lexflag = lexmin (D, Q, ZERO); /* see if lexmin basis */ if (Q->debug) printA (D, Q); } /* Check to see if necessary to resize */ if (Q->inputd > D->d) *D_p = resize (D, Q); return TRUE; } /********* end of lrs_getfirstbasis ***************/ long getabasis2 (lrs_dic * P, lrs_dat * Q, lrs_dic * P2orig, long order[]) /* Pivot Ax<=b to standard form */ /*Try to find a starting basis by pivoting in the variables x[1]..x[d] */ /*If there are any input linearities, these appear first in order[] */ /* Steps: (a) Try to pivot out basic variables using order */ /* Stop if some linearity cannot be made to leave basis */ /* (b) Permanently remove the cobasic indices of linearities */ /* (c) If some decision variable cobasic, it is a linearity, */ /* and will be removed. */ { long i, j, k; /* assign local variables to structures */ lrs_mp_matrix A = P->A; long *B = P->B; long *C = P->C; long *Row = P->Row; long *Col = P->Col; long *linearity = Q->linearity; long *redundcol = Q->redundcol; long m, d, nlinearity; long nredundcol = 0L; /* will be calculated here */ static long firsttime=TRUE; static long *linindex; m = P->m; d = P->d; nlinearity = Q->nlinearity; if(firsttime) { firsttime = FALSE; linindex = (long int *) calloc ((m + d + 2), sizeof (long)); } else /* after first time we update the change in linearities from the last time, saving many pivots */ { for(i=1;i<=m+d;i++) linindex[i]=FALSE; if(Q->debug) fprintf(lrs_ofp,"\nlindex ="); for(i=0;idebug) fprintf(lrs_ofp," %ld",d+linearity[i]); } for(i=1;i<=m;i++) { if(linindex[B[i]]) /* pivot out unwanted linearities */ { k=0; while(k B[j]) /* decrease i or we may skip a linearity */ i--; pivot (P, Q, j, k); update (P, Q, &j, &k); } else if(Q->debug || Q->verbose) fprintf(lrs_ofp,"\n*Couldn't remove linearity i=%ld B[i]=%ld",i,B[i]); /* this is not necessarily an error, eg. two identical rows/cols in payoff matrix */ } } goto hotstart; } /* standard lrs processing is done on only the first call to getabasis2 */ if (Q->debug) { fprintf (lrs_ofp, "\ngetabasis from inequalities given in order"); for (i = 0; i < m; i++) fprintf (lrs_ofp, " %ld", order[i]); } for (j = 0; j < m; j++) { i = 0; while (i <= m && B[i] != d + order[j]) i++; /* find leaving basis index i */ if (j < nlinearity && i > m) /* cannot pivot linearity to cobasis */ { if (Q->debug) printA (P, Q); #ifndef LRS_QUIET fprintf (lrs_ofp, "\nCannot find linearity in the basis"); #endif return FALSE; } if (i <= m) { /* try to do a pivot */ k = 0; while (C[k] <= d && zero (A[Row[i]][Col[k]])) k++; if (C[k] <= d) { pivot (P, Q, i, k); update (P, Q, &i, &k); } else if (j < nlinearity) { /* cannot pivot linearity to cobasis */ if (zero (A[Row[i]][0])) { #ifndef LRS_QUIET fprintf (lrs_ofp, "\n*Input linearity in row %ld is redundant--skipped", order[j]); #endif linearity[j] = 0; } else { if (Q->debug) printA (P, Q); if (Q->verbose) fprintf (lrs_ofp, "\nInconsistent linearities"); return FALSE; } } /* end if j < nlinearity */ } /* end of if i <= m .... */ } /* end of for */ /* update linearity array to get rid of redundancies */ i = 0; k = 0; /* counters for linearities */ while (k < nlinearity) { while (k < nlinearity && linearity[k] == 0) k++; if (k < nlinearity) linearity[i++] = linearity[k++]; } nlinearity = i; /* column dependencies now can be recorded */ /* redundcol contains input column number 0..n-1 where redundancy is */ k = 0; while (k < d && C[k] <= d) { if (C[k] <= d) /* decision variable still in cobasis */ redundcol[nredundcol++] = C[k] - Q->hull; /* adjust for hull indices */ k++; } /* now we know how many decision variables remain in problem */ Q->nredundcol = nredundcol; Q->lastdv = d - nredundcol; /* if not first time we continue from here after loading dictionary */ hotstart: if (Q->debug) { fprintf (lrs_ofp, "\nend of first phase of getabasis2: "); fprintf (lrs_ofp, "lastdv=%ld nredundcol=%ld", Q->lastdv, Q->nredundcol); fprintf (lrs_ofp, "\nredundant cobases:"); for (i = 0; i < nredundcol; i++) fprintf (lrs_ofp, " %ld", redundcol[i]); printA (P, Q); } /* here we save dictionary for use next time, *before* we resize */ copy_dict(Q,P2orig,P); /* Remove linearities from cobasis for rest of computation */ /* This is done in order so indexing is not screwed up */ for (i = 0; i < nlinearity; i++) { /* find cobasic index */ k = 0; while (k < d && C[k] != linearity[i] + d) k++; if (k >= d) { if(Q->debug || Q->verbose) fprintf (lrs_ofp, "\nCould not remove cobasic index"); /* not neccesarily an error as eg., could be repeated row/col in payoff */ } else { removecobasicindex (P, Q, k); d = P->d; } } if (Q->debug && nlinearity > 0) printA (P, Q); /* set index value for first slack variable */ /* Check feasability */ if (Q->givenstart) { i = Q->lastdv + 1; while (i <= m && !negative (A[Row[i]][0])) i++; if (i <= m) fprintf (lrs_ofp, "\n*Infeasible startingcobasis - will be modified"); } return TRUE; } /* end of getabasis2 */ //========================================================================== // Outputting equilibria //========================================================================== // This is just a modified 'prat' from lrsmp.c void printrat (char name[], lrs_mp Nin, lrs_mp Din) /*reduce and print Nin/Din */ { lrs_mp Nt, Dt; long i; fprintf (stdout, "%s", name); /* reduce fraction */ copy (Nt, Nin); copy (Dt, Din); reduce (Nt, Dt); /* print out */ if (sign (Nin) * sign (Din) == NEG) fprintf (stdout, "-"); // else // fprintf (stdout, ""); fprintf (stdout, "%lu", Nt[length (Nt) - 1]); for (i = length (Nt) - 2; i >= 1; i--) fprintf (stdout, FORMAT, Nt[i]); if (!(Dt[0] == 2 && Dt[1] == 1)) /* rational */ { fprintf (stdout, "/"); fprintf (stdout, "%lu", Dt[length (Dt) - 1]); for (i = length (Dt) - 2; i >= 1; i--) fprintf (stdout, FORMAT, Dt[i]); } } void nashoutput(lrs_dat *Q1, lrs_mp_vector output1, lrs_dat *Q2, lrs_mp_vector output2, const StrategySupport &p_support) { std::cout << "NE"; // The -1 is because the last entry in the vector is the payoff // of the other player long i = 1; GamePlayer player1 = p_support.GetGame()->GetPlayer(1); for (int j = 1; j <= player1->NumStrategies(); j++) { if (p_support.Contains(player1->GetStrategy(j))) { std::cout << ","; printrat("", output1[i++], output1[0]); } else { std::cout << ",0"; } } i = 1; GamePlayer player2 = p_support.GetGame()->GetPlayer(2); for (int j = 1; j <= player2->NumStrategies(); j++) { if (p_support.Contains(player2->GetStrategy(j))) { std::cout << ","; printrat("", output2[i++], output2[0]); } else { std::cout << ",0"; } } std::cout << std::endl; fflush(stdout); }