/*******************************************************/
/* lrsnashlib is a library of routines for computing   */
/* computing all nash equilibria for two person games  */
/* given by mxn payoff matrices A,B                    */
/*                                                     */
/*                                                     */
/* Main user callable function is                      */
/*         lrs_solve_nash(game *g)                     */
/*                                                     */
/* Requires lrsnashlib.h lrslib.h lrslib.c             */
/*                                                     */
/* Sample driver: lrsnash.c                            */
/* Derived from nash.c in lrslib-060                   */
/* by Terje Lensberg, October 26, 2015:                */
/*******************************************************/

#include <stdio.h>
#include <string.h>
#include "lrsdriver.h"
#include "lrslib.h"
#include "lrsnashlib.h"

static long FirstTime; /* set this to true for every new game to be solved */

long Debug_flag;
long Verbose_flag;

//========================================================================
// Standard solver. Modified version of main() from lrsNash
//========================================================================
int lrs_solve_nash(game * g)
{
  lrs_dic *P1;             /* 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_mp_matrix A2orig;
  lrs_dic *P2orig;              /* we will save player 2's dictionary in getabasis      */

  long *linindex;               /* for faster restart of player 2                       */

  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 1: Allocate lrs_dat, lrs_dic and set up the problem                      */
/*********************************************************************************/
  FirstTime=TRUE;                       /* This is done for each new game */

  Q1 = lrs_alloc_dat("LRS globals");    /* allocate and init structure for static problem data */
  if (Q1 == NULL) {
    return 0;
  }

  Q1->nash = TRUE;
  Q1->n = g->nstrats[ROW] + 2;
  Q1->m = g->nstrats[ROW] + g->nstrats[COL] + 1;

  Q1->debug = Debug_flag;
  Q1->verbose = Verbose_flag;

  P1 = lrs_alloc_dic(Q1);       /* allocate and initialize lrs_dic */
  if (P1 == NULL) {
    return 0;
  }

  BuildRep(P1, Q1, g, 1, 0);

  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 0;
  }

  Q2->debug = Debug_flag;
  Q2->verbose = Verbose_flag;

  Q2->nash = TRUE;
  Q2->n = g->nstrats[COL] + 2;
  Q2->m = g->nstrats[ROW] + g->nstrats[COL] + 1;

  P2orig = lrs_alloc_dic(Q2);   /* allocate and initialize lrs_dic */
  if (P2orig == NULL) {
    return 0;
  }
  BuildRep(P2orig, Q2, g, 0, 1);

  A2orig = P2orig->A;

  output2 = lrs_alloc_mp_vector(Q1->n + Q1->m); /* output holds one line of output from dictionary     */

  linindex = calloc((P2orig->m + P2orig->d + 2), sizeof(long)); /* for next time */

  fprintf(lrs_ofp, "\n");
//  fprintf (lrs_ofp, "***** %ld %ld rational\n", Q1->n, Q2->n);

/*********************************************************************************/
/* 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 1;

  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, output2, linindex);
      if (numequilib > oldnum || Q1->verbose) {
        if (Q1->verbose)
          prat(" \np2's obj value: ", P1->objnum, P1->objden);
        lrs_nashoutput(Q1, output1, 1L);
        fprintf(lrs_ofp, "\n");
      }
    }
  }
  while (lrs_getnextbasis(&P1, Q1, prune));

  fprintf(lrs_ofp, "*Number of equilibria found: %ld", numequilib);
  fprintf(lrs_ofp, "\n*Player 1: vertices=%ld bases=%ld pivots=%ld", Q1->count[1], Q1->count[2], Q1->count[3]);
  fprintf(lrs_ofp, "\n*Player 2: vertices=%ld bases=%ld pivots=%ld", Q2->count[1], Q2->count[2], Q2->count[3]);

  lrs_clear_mp_vector(output1, Q1->m + Q1->n);
  lrs_clear_mp_vector(output2, Q1->m + Q1->n);

  lrs_free_dic(P1, Q1);         /* deallocate lrs_dic */
  lrs_free_dat(Q1);             /* deallocate lrs_dat */

/* 2015.10.10  new code to clear P2orig */
  Q2->Qhead = P2orig;           /* reset this or you crash free_dic */
  P2orig->A = A2orig;           /* reset this or you crash free_dic */

  lrs_free_dic(P2orig, Q2);     /* deallocate lrs_dic */
  lrs_free_dat(Q2);             /* deallocate lrs_dat */

  free(linindex);

//  lrs_close("nash:");
	fprintf(lrs_ofp, "\n");
  return 0;
}

/*********************************************/
/* 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 output, long linindex[])
{

  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 (Q1->nlinearity == 0 || j < Q1->linearity[0])
        linearity[nlinearity++] = j;
    }
  }
/* add back in the linearity for probs summing to one */
  if (Q1->nlinearity > 0)
    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, linindex))
    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, output, col)) {
      if (Q2->verbose)
        prat(" \np1's obj value: ", P2->objnum, P2->objden);
      if (lrs_nashoutput(Q2, output, 2L))
        (*numequilib)++;
    }
  }
  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, long linindex[])
/* 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, *Col;
  long *inequality;
  long *linearity;
  long hull = Q->hull;
  long m, d, lastdv, nlinearity, nredundcol;

  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;
  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, linindex)) {
    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) {
    const unsigned int Qn = Q->n;
    *Lin = lrs_alloc_mp_matrix(nredundcol, Qn);

    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)) {
        lrs_clear_mp_matrix(*Lin, nredundcol, Qn);
        return FALSE;
      }
    }
  }                             /* end if nredundcol > 0 */

  if (Q->verbose) {
    fprintf(lrs_ofp, "\nNumber of pivots for starting dictionary: %ld", 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");
    }
    return FALSE;
  }

  if (Q->verbose) {
    fprintf(lrs_ofp, "\nNumber of pivots for feasible solution: %ld", 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[], long linindex[])

/* 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.                                            */
{
/* 2015.10.10 linindex now preallocated and received as parameter so we can free it */

//  static long firsttime = TRUE; /* stays true until first valid dictionary built */

  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 */

  m = P->m;
  d = P->d;
  nlinearity = Q->nlinearity;
//2015.9.15
  /* after first time we update the change in linearities from the last time, saving many pivots */
  if (!FirstTime) {
    for (i = 1; i <= m + d; i++)
      linindex[i] = FALSE;
    if (Q->debug)
      fprintf(lrs_ofp, "\nlindex =");
    for (i = 0; i < nlinearity; i++) {
      linindex[d + linearity[i]] = TRUE;
      if (Q->debug)
        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 < d && (linindex[C[k]] || zero(A[Row[i]][Col[k]])))
          k++;

        if (k < d) {
          j = i;                /* note this index changes in update, cannot use i!) */

          if (C[k] > B[j])      /* decrease i or we may skip a linearity */
            i--;
          pivot(P, Q, j, k);
          update(P, Q, &j, &k);
        }
        else {
          /* this is not necessarily an error, eg. two identical rows/cols in payoff matrix */
          if (!zero(A[Row[i]][0])) {    /* error condition */
            if (Q->debug || Q->verbose) {
              fprintf(lrs_ofp, "\n*Infeasible linearity i=%ld B[i]=%ld", i, B[i]);
              if (Q->debug)
                printA(P, Q);
            }
            return (FALSE);
          }
          if (Q->debug || Q->verbose) {
            fprintf(lrs_ofp, "\n*Couldn't remove linearity i=%ld B[i]=%ld", i, B[i]);
          }
        }

      }                         /* if linindex */
    }                           /* for i   .. */
  }
  else {                        /* we have not had a successful dictionary built from the given linearities */

/* 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, "*Input linearity in row %ld is redundant--skipped\n", order[j]);
#endif
            linearity[j] = 0;
          }
          else {
            if (Q->debug)
              printA(P, Q);
            if (Q->debug || 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;
/* lrs bug fix, 2009.6.27, nash 2015.9.16 */
    Q->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;
/* 2015.9.15 bug fix : we needed first *successful* time */
    FirstTime = FALSE;
  }                             /* else firsttime ... we have built a dictionary from the given linearities */

  /* we continue from here after loading dictionary */

  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 */

long lrs_nashoutput(lrs_dat * Q, lrs_mp_vector output, long player)
{
  long i;
  long origin = TRUE;

/* do not print the origin for either player */
  for (i = 1; i < Q->n; i++)
    if (!zero(output[i]))
      origin = FALSE;

  if (origin)
    return FALSE;

  fprintf(lrs_ofp, "%ld ", player);
  for (i = 1; i < Q->n; i++)
    prat("", output[i], output[0]);
  fprintf(lrs_ofp, "\n");
  fflush(lrs_ofp);
  return TRUE;
}                               /* end lrs_nashoutput */



//========================================================================
// Old style solver. Included for backward compatibility
//========================================================================
int lrs_solve_nash_legacy (int argc, char *argv[])
// Handles legacy input files
{
  lrs_dic *P1;			/* 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_mp_matrix A2orig;
  lrs_dic *P2orig;              /* we will save player 2's dictionary in getabasis      */

  long *linindex;               /* for faster restart of player 2                       */

  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. */

  if(argc <= 2 )
  { printf("Usage: %s input1 input2 [outputfile]     \n", argv[0]);
	  return 1;
  }

/***************************************************
 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 ("\n*nash:"))
    return 1;

/*********************************************************************************/
/* 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 1;
  Q1->nash=TRUE;

  if (!lrs_read_dat (Q1, argc, argv))	/* read first part of problem data to get dimensions   */
    return 1;                   	/* and problem type: H- or V- input representation     */
  strcpy(Q1->fname,"nash");     /* program name */
  P1 = lrs_alloc_dic (Q1);	/* allocate and initialize lrs_dic                     */
  if (P1 == NULL)
    return 1;

  if (!lrs_read_dic (P1, Q1))	/* read remainder of input to setup P1 and Q1           */
    return 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                                   */

  printf ("\n*Second input taken from file %s\n", argv[2]);
  Q2 = lrs_alloc_dat ("LRS globals"); 
  if (Q2 == NULL)
          return 1;

  strcpy(Q2->fname,"nash");     /* program name */
  Q2->nash=TRUE;

  if (!lrs_read_dat (Q2, 2, argv))	/* read first part of problem data to get dimensions   */
    return 1;                   	/* and problem type: H- or V- input representation     */

  if (Q2->nlinearity > 0)
      free(Q2->linearity);               /* we will start again */
  Q2->linearity  = CALLOC ((Q2->m + 2), sizeof (long));

  P2orig = lrs_alloc_dic (Q2);	     /* allocate and initialize lrs_dic                     */
  if (P2orig == NULL)
         return 1;
  if (!lrs_read_dic (P2orig, Q2))        /* read remainder of input to setup P2 and Q2          */
    return 1;
  A2orig = P2orig->A;

  output2 = lrs_alloc_mp_vector (Q1->n + Q1->m);     /* output holds one line of output from dictionary     */

  linindex = calloc ((P2orig->m + P2orig->d + 2), sizeof (long)); /* for next time*/

  fprintf (lrs_ofp, "\n***** %ld %ld rational\n", Q1->n, Q2->n);


/*********************************************************************************/
/* 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 1;

  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,output2,linindex);
	   if (numequilib > oldnum || Q1->verbose)
	      {
                if(Q1->verbose)
                  prat(" \np2's obj value: ",P1->objnum,P1->objden);
                lrs_nashoutput (Q1, output1, 1L);
       	        fprintf (lrs_ofp, "\n");
	      }
	}
    }
  while (lrs_getnextbasis (&P1, Q1, prune));

  fprintf(lrs_ofp,"\n*Number of equilibria found: %ld",numequilib);
  fprintf (lrs_ofp,"\n*Player 1: vertices=%ld bases=%ld pivots=%ld", Q1->count[1],  Q1->count[2],Q1->count[3]);
  fprintf (lrs_ofp,"\n*Player 2: vertices=%ld bases=%ld pivots=%ld", Q2->count[1],  Q2->count[2],Q2->count[3]);

  lrs_clear_mp_vector(output1, Q1->m + Q1->n);
  lrs_clear_mp_vector(output2, Q1->m + Q1->n);

  lrs_free_dic (P1,Q1);          /* deallocate lrs_dic */
  lrs_free_dat (Q1);             /* deallocate lrs_dat */

/* 2015.10.10  new code to clear P2orig */
  Q2->Qhead = P2orig;                 /* reset this or you crash free_dic */
  P2orig->A=A2orig;                   /* reset this or you crash free_dic */

  lrs_free_dic (P2orig,Q2);     /* deallocate lrs_dic */
  lrs_free_dat (Q2);            /* deallocate lrs_dat */

  free (linindex);

  lrs_close ("nash:");

  return 0;
}

/*********************************************/
/* end of nash driver                        */
/*********************************************/



//==========================================================================
//   Building the problem representations (adapted from Gambit-enummixed)
//==========================================================================

//
// 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];
  long row, col;

  for (row = firstRow; row <= lastRow; row++) {
    num[0] = 0;
    den[0] = 1;

    for (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);
  }
}


long str2rat (lrs_mp Na, lrs_mp Da, char *str)	{
/* Based on readrat in lrsgmp.c           */
/* convert rational or integer to lrs_mp  */
/* returns true if denominator is not one */

  char num[MAXINPUT], den[MAXINPUT];

  atoaa (str, num, den);		/*convert rational to num/dem strings */
  atomp (num, Na);
  if (den[0] == '\0')
    {
      itomp (1L, Da);
      return (FALSE);
    }
  atomp (den, Da);
  return (TRUE);
}



//----------------------------------------------------------------------------------------//
void FillConstraintRows(lrs_dic * P, lrs_dat * Q, const game * g, int p1, int p2, int firstRow)
{

  lrs_mp_vector Num, Den;
  char *onePayoff;
  int row, s, t, d;

  d = P->d;  // Should equal g->nstrats[p2] + 1?

  Num = lrs_alloc_mp_vector(d+1);
  Den = lrs_alloc_mp_vector(d+1);

  for (row = firstRow; row < firstRow + g->nstrats[p1]; row++) {
		itomp (ZERO, Num[0]);
		itomp (ONE,  Den[0]);

    s = row - firstRow;
    for (t = 0; t < g->nstrats[p2]; t++) {
			onePayoff = p1 == ROW ? g->payoff[p1][s][t] : g->payoff[p1][t][s];
			str2rat(Num[t + 1], Den[t + 1], onePayoff);
			if(!zero(Num[t + 1]))
				changesign(Num[t + 1]);
    }

		itomp (ONE, Num[g->nstrats[p2] + 1]);
		itomp (ONE, Den[g->nstrats[p2] + 1]);

    lrs_set_row_mp(P, Q, row, Num, Den, GE);
  }

  lrs_clear_mp_vector(Num,d+1);
  lrs_clear_mp_vector(Den,d+1);
}


//----------------------------------------------------------------------------------------//
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];
  int i;

  num[0] = -1;
  den[0] = 1;

  for (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);
}

//
// TL added this to get first row of ones. Don't know if it's needed
//----------------------------------------------------------------------------------------//
void FillFirstRow(lrs_dic * P, lrs_dat * Q, int n)
{
  const int MAXCOL = 1000;      /* maximum number of columns */
  long num[MAXCOL], den[MAXCOL];
  int i;

  for (i = 0; i < n; i++) {
    num[i] = 1;
    den[i] = 1;
  }
  lrs_set_row(P, Q, 0, num, den, GE);
}

//
// Build the H-representation for player p1
//----------------------------------------------------------------------------------------//
void BuildRep(lrs_dic * P, lrs_dat * Q, const game * g, int p1, int p2)
{
  long m = Q->m;                /* number of inequalities      */
  long n = Q->n;

  if (p1 == 0) {
    FillConstraintRows(P, Q, g, p1, p2, 1);
    FillNonnegativityRows(P, Q, g->nstrats[p1] + 1, g->nstrats[ROW] + g->nstrats[COL], n);
  }
  else {
    FillNonnegativityRows(P, Q, 1, g->nstrats[p2], n);
    FillConstraintRows(P, Q, g, p1, p2, g->nstrats[p2] + 1);    // 1 here
  }
  FillLinearityRow(P, Q, m, n);

// TL added this to get first row of ones. (Is this necessary?)
  FillFirstRow(P, Q, n);
}

//----------------------------------------------------------------------------------------//
void printGame(game * g)
{
  int s, t, pos, len;
  int *fwidth[2];

/* Storage for field witdths. g->nstrats[COL] columns for both players */

  fwidth[ROW] = (int *)calloc(g->nstrats[COL], sizeof(int));
  fwidth[COL] = (int *)calloc(g->nstrats[COL], sizeof(int));

/* Get column widths for output*/

	for(pos=0; pos<2; pos++) {
  	for (t = 0; t < g->nstrats[COL]; t++) {
			fwidth[pos][t] = 0;
  		for (s = 0; s < g->nstrats[ROW]; s++) {
				len = strlen(g->payoff[pos][s][t]);
				if(len > fwidth[pos][t])
					fwidth[pos][t] = len;
			}
		}
	}
/* print payoffs */ 

  fprintf(lrs_ofp, "\n--------------------------------------------------------------------------------\n");
  fprintf(lrs_ofp, "%s payoff matrix:\n", g->name);
  for (s = 0; s < g->nstrats[ROW]; s++) {
    for (t = 0; t < g->nstrats[COL]; t++)
			fprintf(lrs_ofp, "%*s, %-*s  ", fwidth[ROW][t], g->payoff[ROW][s][t], fwidth[COL][t], g->payoff[COL][s][t]);
    fprintf(lrs_ofp, "\n");
	}

  fprintf(lrs_ofp, "\nNash equilibria:\n");
  fflush(lrs_ofp);

	free(fwidth[ROW]);
	free(fwidth[COL]);
}


void resetNashSolver() { FirstTime = TRUE; }
/******************** end of lrsnashlib.c ***************************/
