/************************************************************************
* retroLP solves linear programs using the simplex method.             *
* Copyright (C) 2001, 2003, 2005 Gavriel Yarmish & Richard Van Slyke.  *
* For further information, and gpl licensing, see the end of this file.*
************************************************************************/

//------------------------FILE FPARSE--------------------------
// 3/26/05 Changed so that readmps could be integrated 
//         into retroLP
// 8/31/04 Correct bug in error reporting for unknown row
// 8/6/01  Write out row and name structures for output program
//        (lpbV1)

// The MPS format is somewhat ambiguous. We follow
// the MINOS conventions (Bruce A. Murtagh and Michael A.
// Saunders, MINOS 5.5 USER'S GUIDE, Technical Report SOL 83-20R
// Revised July, 1998. We make the following additional
// assumptions
// 1.   There is exactly one objective function
// 2.   It corresponds to the FIRST row with code "N"
// 3.   There is exactly one RHS
// 4.   The right hand side may be empty (all zero), but "RHS"
//      must appear; We assume only one RHS; if there is more
//      than one, we only look at the first.
// 5.   If there are any non-zero elements of the RHS the column
//      of elements must be given a name.
// 6.   The bounds section is optional
// 7.   Lines in the bounds section for free ("FR") and lower
//      bound to -infinity ("MI") should not have numeric values
// 8.   The RANGES section is optional, but if there is one, we
//      assume there is only one set of ranges; if there is more
//      than one we only look at the first.
// 9.   The BOUNDS section is optional, but if there is one, we
//      assume there is only one RHS; if there is more than one,
//      we only look at the first.

#pragma warning(disable: 4786)


#include "mps.h"
#include "simplex.h"
#include "params.h"
#include <map>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <cmath>


/*
double *allocate_dvector(long);
short lparse(std::FILE *, std::string &, std::string &, std::string &, std::string &,
  double &, double &, std::string &, long &);
LP_state * make_arrays(long, long);
int upper(int, std::string &);
void init_brange(LP_state *);

/**/
// FUNCTIONS IN THIS FILE
LP_state * fparse(FILE *, long, long);
short rows(FILE *);
short columns(std::FILE *, double *, double *);
short rhs(std::FILE *);
short ranges(std::FILE *);
short bounds(std::FILE *);
double scale(long , long , double *, double *);
void problem_size(std::FILE * , long *, long *, long *);

// EXTERNAL FUNCTIONS USED
int upper(int, std::string &);
void free_arrays(LP_state *);
short lparse(std::FILE *, std::string &, std::string &, std::string &, std::string &,
  double &, double &, std::string &, long &);
LP_state * make_arrays(long, long);
void init_brange(LP_state *);
double *allocate_dvector(long);
char * allocate_strvector(int, long);
int to_file(FILE *, LP_state *);
/**/


// VARIABLES & STRUCTURES SHARED BY FUNCTIONS IN THIS FILE
// Structures for row and column maps

//namespace makedll {
//public class Fparse { 

struct row_list
       {
          long index;
          short type;
       };
std::map<std::string, row_list>rmap;
std::map<std::string, row_list>::const_iterator ritr;
struct col_list
       {
         long index;
       };
std::map<std::string, col_list>cmap;
std::map<std::string, col_list>::const_iterator citr;

static long lineno=0;
LP_state *lp;
// If error encountered "errors" is set, and we exit
// at end of fparse, returning NULL.
bool errors=false;

//====================== FPARSE ======================


LP_state *  fparse( FILE *  file, long m, long n, int skal)
{
    long row, col, k;
    bool if_scale = 0;
	
	if (skal==1) if_scale=1;

	std::string key, name0, name1, name2, buffer;
    double value1, value2;
    short kw;
    double *rscale = allocate_dvector(m);
    for(row=0;row<=m;row++)rscale[row]=0.0;
    double *cscale = allocate_dvector(n);

    lp  = NULL;

// Allocate arrays
    lp = make_arrays(m, n); // Freed from main
    lp->m = m;
    lp->n = n;
    lp->mm = m + 1;
 
// Put bounds to defaults in case there is no bounds data
    for (col=1;col<=lp->n;col++)
    {
         lp->nl[col] = 0.0;
         lp->nu[col] = DBL_MAX;
         lp->ntype[col] = LBOUNDED;
         lp->x[col] = 0.0;
         lp->jnonbasic[col] = col;
         lp->nrange[col] = ATLOWER;
    }

// Initialize ibasics
    for (row=1; row <=lp->m; row++) lp->ibasic[row] = lp->n + row;
// Save problem name
   if(NAME!=lparse(file, key, name0, name1, name2,
       value1, value2, buffer, lineno))
    {
      printf("NAME missing in input file\n");
      exit(6);
    }

    strncpy(lp->name,buffer.substr(14,8).c_str(),9);
// If scaled add "(scaled)" to problem name
   if(if_scale)strcat(lp->name, "(scaled)");
   if(ROWS!=lparse(file, key, name0, name1, name2,
    value1, value2,buffer,lineno))
    {
      printf("Line: %ld; File not in MPS format;\
       expected ROWS key word\n", lineno );
      printf("Got: %s\n",buffer.c_str());
      errors=true;
    }
// Read in rows here
// Debugging printout
    printf("**************** ROWS ****************\n");
    if(COLUMNS!=rows(file))
// Check for COLUMNS key word
    {
      printf("Line: %ld; File not in MPS format;\
       expected COLUMNS key word\n", lineno );
      printf("Got: %s\n",buffer.c_str());
      errors=true;
    }
// Read in columns here
    printf("************** COLUMNS ***************\n");
    if(RHS!=columns(file,rscale,cscale))
    {
// Check for RHS key word
      printf("Line: %ld; File not in MPS format;\
       expected RHS key word\n", lineno );
      errors=true;
    }
// Read in right hand side here
    printf("**************** RHS *****************\n");
   kw = rhs(file);
// For now put zeros in Phase I objective.
    for(col=0;col<=lp->n;col++)lp->a[col][lp->mm] = 0.0;
    printf("\n");
// Check for RANGES key word
   if(kw == RANGES )
    {
      printf("*************** RANGES ***************\n");
      kw = ranges(file);
    }
// Check for BOUNDS key word
   if(kw == BOUNDS)
// If bounds section exists; read here
    {
    printf("*************** BOUNDS ***************\n");

       kw = bounds(file);
    }
// Check for ENDATA key word
   if(kw != ENDATA )
    {
      printf("Line: %ld; File not in MPS format;\
       expected ENDATA key word\n", lineno );
      printf("Got: %s\n",buffer.c_str());
      errors=true;
    }
    printf("*************** ENDATA ***************\n");
    if(if_scale)
      {
	double objfactor = scale(m,n,rscale,cscale);
	printf("************** SCALING ***************\n");
	free(rscale);
	free(cscale);
      }
// More basis initialization
    init_brange(lp);

// Construct row and name structures
// Key word for lpb version
   strcpy(lp->lpb_version,"lpbV1");
// Row names:
// Loop through row structure and fill in names in index order
   for (ritr = rmap.begin(); ritr != rmap.end(); ++ritr)
   {
      k= 9*((ritr->second.index) + lp->n);
      strncpy(&(lp->names[k]), ritr->first.c_str(),9);
   }
// Write row names to outfile
// For debugging; for now write to standard out also
#if DEBUG
   printf("row names in order of appearance\n");
   for(ir=0; ir<=lp->m; ++ir)
   {
      printf("%s\n", &lp->names[9*(ir+lp->n)]);
   }
#endif
// Column names:
// Loop through column structure and fill in names in index order
   for (citr = cmap.begin(); citr != cmap.end(); ++citr)
   {
      k= (citr->second.index)*9;
      strncpy(&(lp->names[k]), citr->first.c_str(),9);
   }
// Write column names to outfile
// For debugging; for now write to standard out also
#if DEBUG
   printf("column names in order of appearance\n");
   for(jr=1; jr<=lp->n; ++jr)
   {
      printf("%s\n", &lp->names[9*jr]);
   }
#endif
   return(lp);
}
//======================= ROWS =======================
short rows( FILE * file)
{
   long mrow = 0;
   std::string key, name0, name1, name2, buffer;
   double value1, value2;
   short bytes, type;
   short obj = -1;
   // Enter rows
   while((bytes = lparse(file, key, name0, name1, name2,
    value1, value2,buffer,lineno))>7)
    {
// Set type index based on key

    if(key.find_first_of("Ee")!=std::string::npos)type = E;
      else if(key.find_first_of("Gg")!=std::string::npos)type = G;
        else if(key.find_first_of("Ll")!=std::string::npos)type = L;
          else if(key.find_first_of("Nn")!=std::string::npos)type = N;
            else
          {
            printf("Unknown Row Type in line %ld\n",lineno);
            printf("%s\n",buffer.c_str());
          };
    mrow++;
    if(name0.length()==0)
    {
      errors=true;
      printf("Expected row name missing at line no: &ld\n", lineno);
    }
// Process row in case statement based on type
    switch (type)
    {
      case E: // Equation; artificial must end up 0
// Add to row list
        rmap[name0].index = mrow;
        rmap[name0].type = E;
        lp->btype[mrow]=FIXED;
        lp->bl[mrow]=0.0;
        lp->bu[mrow]=0.0;
#if DEBUG
        printf(" E ");
#endif
        break;
      case G: // Relation must be >= 0; artificial
              // must be <= 0. Remember we use tableau.
// Add to row list
        rmap[name0].index = mrow;
        rmap[name0].type = G;
        lp->btype[mrow]=UBOUNDED;
        lp->bl[mrow]= -DBL_MAX;
        lp->bu[mrow]=0.0;
#if DEBUG
        printf(" G ");
#endif
        break;
      case L: // Relation must be <= 0; artificial
              // must be >= 0. Remember we use tableau.
// Add to row list
        rmap[name0].index = mrow;
        rmap[name0].type = L;
        lp->btype[mrow]=LBOUNDED;
        lp->bl[mrow]=0.0;
        lp->bu[mrow]=DBL_MAX;
#if DEBUG
        printf(" L ");
#endif
        break;
      case N: // Either objective or Free
// If first N type; this is the objective
      if(obj==-1)
      {
// Add to row list as row 0
        mrow--;
        obj=0;
        rmap[name0].index = 0;
        rmap[name0].type = N;

#if DEBUG
        printf(" N ");
#endif
        break;
      }
// Free variable
// Add to row list
      else
      {
        rmap[name0].index = mrow;
        rmap[name0].type = N;
        lp->btype[mrow]=FREE;
        lp->bl[mrow] = -DBL_MAX;
        lp->bu[mrow] = DBL_MAX;
#if DEBUG
        printf(" N ");
#endif
        break;
       }

      default:
        printf(" \nUnknown relation type: %s\n",type);
        mrow--;
        exit(12);
      }
      // for debugging
#if DEBUG
      long x;
      x=rmap[name0].index;
      printf(" row number for %s is %ld ", name0.c_str(), x);
      printf("\n");
#endif
   }
   return bytes;
}
//======================== COLUMNS ================
short columns(FILE * file, double *rscale, double *cscale)
{
  long i, ncol=0, e=0;
  short bytes;
  std::string key, name0, name1, name2, buffer;
  double value1, value2;
  std::string oldname;
// Enter columns and elements
  while((bytes = lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))>7)
    {
      if(name0.length()==0)
      {
        errors=true;
        printf("Expected column name missing at line no: &ld\n", lineno);
      }
      if(name0!=oldname)
// New column
      {
// Check to see if old column is all zeros
        if((cscale[ncol]==0.0) && (oldname.length() != 0))
        {
          printf("WARNING: Column %s, number %ld has no nonzero entries\n",oldname.c_str(),ncol);
        }
        ncol++;
        oldname = name0;
        cscale[ncol]=0.0;
// Store column name in map
        cmap[name0].index = ncol;
      }
#if DEBUG
// For debugging
      long x;
      x = cmap[name0].index;
      printf(" Line no: %ld; col name: %s; col number: %ld \n",
       lineno, name0.c_str(), x);
#endif
      if(bytes==11||bytes==13)
// Fetch row index for name1
      {
        if((ritr=rmap.find(name1))==rmap.end())
        {
          printf("Unknown row name %s in line %ld\n"
           ,name1.c_str(),lineno);
          errors=true;
        }
        else 
		{
			i=((ritr->second).index);
			e++;
			// If objective (i=0), may need reversal if maximizing
			lp->a[ncol][i]=-(i?1.0:maxfactor)*value1;
			if(fabs(value1)> rscale[i])
			rscale[i] = fabs(value1);
			if(fabs(value1)>cscale[ncol])
			cscale[ncol]=fabs(value1);
		}
#if DEBUG
// For debugging
        x=rmap[name1].index;
        printf("value(s): row name: %s; row number: %ld; value: %e "
          , name1.c_str(), x, value1);
#endif
      }
      if(bytes==13)
// Fetch row index for name2
      {
        e++;
        if((ritr=rmap.find(name2))==rmap.end())
        {
          printf("Unknown row name %s in line %ld\n",
            name2.c_str(),lineno);
          errors=true;
        }
        else 
		{
			i=(ritr->second).index;
			// If objective (i=0), may need reversal if maximizing
			lp->a[ncol][i]=-(i?1.0:maxfactor)*value2;
			if(fabs(value2)> rscale[i])
				rscale[i] = fabs(value2);
			if(fabs(value2)>cscale[ncol])
				cscale[ncol]=fabs(value2);
		}

#if DEBUG
// For debugging
        x=rmap[name2].index;
        printf("value(s): row name: %s; row number: %ld; value: %e "
          , name2.c_str(), x, value2);
#endif
      }
#if DEBUG
        printf("\n");
#endif
    }
// Check for empty rows
   std::string row_name;
   for (i = 1; i <= lp->m; i++)
   {
     if(rscale[i]==0.0)
     {
       // Look up row name
       for(ritr = rmap.begin(); ritr != rmap.end(); ++ritr)
       {
         if((ritr->second).index == i)
         {
           row_name = ritr->first;
         }
       }
       printf("WARNING: Row %s, number %ld has no nonzero entries\n",row_name.c_str(),i);
     }
   }

// End check for empty rows
  return bytes;
}
//====================== RHS =======================
short rhs(FILE * file)

//assuming only one RHS
// But we assume there is a name for it.
{
  long i;
  short bytes, nrhs=0;
  std::string key, name0, name1, name2, buffer;
  double value1, value2;
  std::string oldname="         ";
  while((bytes = lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))>7)
    {
      if(name0!=oldname)
// New RHS
      {
// We only look at first RHS
        if(nrhs>0)return 0;
        nrhs++;
        oldname=name0;
      }
      if(bytes==11||bytes==13)
// Fetch row index for name1
      {
       if(rmap.find(name1)  == rmap.end())
       {
         printf(" Unrecognized row name: %s \n", name1.c_str());
         exit(101);
       }
       else
	 {
	   i = rmap[name1].index;
	   // If objective (i=0) may need reversal if maximizing
	   lp->a[0][i]=(i?1.0:maxfactor)*value1;
	 }
      }
// For debugging
#if DEBUG
        long x;
        x=rmap[name1].index;
        printf("value(s): row name: %s; row number: %ld; value: %e "
          , name1.c_str(), x, value1);
#endif
      if(bytes==13)
// Fetch row index for name2
      {
       if(rmap.find(name2) == rmap.end())
       {
         printf(" Unrecognized row name: %s \n", name2.c_str());
         exit(102);
       }
       else
	 // If objective (i=0) may need reversal if maximizing
	 {
	   i = rmap[name2].index;
	   lp->a[0][i]=(i?1.0:maxfactor)*value2;
	 }
#if DEBUG
// For debugging
        x=rmap[name2].index;
        printf("value(s): RHS name: %s; row number: %ld; value: %e "
          , name2.c_str(), value2);
#endif
      }
#if DEBUG
        printf("\n");
#endif
    }
  return bytes;
}
//======================== RANGES ================
short ranges(FILE * file)       //assuming only one range set
// But we assume there is a name for it.
{
  long i;
  short bytes, nrngs=0, type;
  std::string key, name0, name1, name2, buffer;
  double value1, value2;
  std::string oldname="         ";
  while((bytes = lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))>7)
    {
      if(name0!=oldname)
// New RANGE
      {
// We only look at first RANGE SET
        if(nrngs>0)return 0;
        nrngs++;
        oldname=name0;
      }
      if(bytes==11||bytes==13)
// Fetch row index for name1
      {
       if(rmap.find(name1)  == rmap.end())
       {
         printf(" Unrecognized row name: %s \n", name1.c_str());
         exit(101);
       }
       else
        i = rmap[name1].index;
        type = rmap[name1].type;
        switch ( type )
        {
          case E:
            lp->btype[i]=BOTHBOUNDS;
            if(value1<0)lp->bl[i] = value1;
            else lp->bu[i] = value1;
            break;
          case G:
            lp->btype[i]=BOTHBOUNDS;
            lp->bl[i] = -fabs(value1);
            break;
          case L:
            lp->btype[i]=BOTHBOUNDS;
            lp->bu[i] = fabs(value1);
            break;
          default:
              printf(" \nUnknown relation type for RANGE: %s\n",type);
              exit(112);

          }

      }
// For debugging
#if DEBUG
        long x;
        x=rmap[name1].index;
        printf("value(s): row name: %s; row number: %ld; value: %e "
          , name1.c_str(), x, value1);
#endif
      if(bytes==13)
// Fetch row index for name2
      {
       if(rmap.find(name2) == rmap.end())
       {
         printf(" Unrecognized row name: %s \n", name2.c_str());
         exit(102);
       }
       else
        i = rmap[name2].index;
        type = rmap[name1].type;
        switch ( type )
        {
          case E:
            lp->btype[i]=BOTHBOUNDS;
            if(value1<0)lp->bl[i]=value2;
            else lp->bu[i]=value1;
            break;
          case G:
            lp->btype[i]=BOTHBOUNDS;
            lp->bl[i]= -fabs(value2);
            lp->bu[i]=0.0;
            break;
          case L:
            lp->btype[i]=BOTHBOUNDS;
            lp->bu[i]= fabs(value2);
            lp->bl[i]=0.0;
            break;
          default:
              printf(" \nUnknown relation type for RANGE: %s\n",type);
              exit(112);

          }

#if DEBUG
// For debugging
        x=rmap[name2].index;
        printf("value(s): RHS name: %s; row number: %ld; value: %e "
          , name2.c_str(), value2);
#endif
      }
#if DEBUG
        printf("\n");
#endif
    }
  return bytes;
}
//=================== BOUNDS ======================
short bounds(FILE * file)
{
   long j;
   short type, bytes, nbounds=0;
   std::string key, name0, name1, name2, buffer;
   std::string oldname="         ";
   double value1, value2;
   while((bytes = lparse(file, key, name0, name1, name2,
    value1, value2,buffer,lineno))>7)
    {
       if(name0!=oldname)
// New column
      {
// We only look at first set of bounds
        if(nbounds>0)return 0;
        nbounds++;
        oldname=name0;
      }
// Set type index based on key
    upper(2,key);
    if(key.find("LO")!=std::string::npos)type = LO;
      else if(key.find("UP")!=std::string::npos)type = UP;
        else if(key.find("FX")!=std::string::npos)type = FX;
          else if(key.find("FR")!=std::string::npos)type = FR;
            else if(key.find("MI")!=std::string::npos)type = MI;
              else if(key.find("PL")!=std::string::npos)type = PL;
                else
          {
            printf("Unknown Bound Type in line %ld\n",lineno);
          }

// Fetch column index j based on name1
        if((citr=cmap.find(name1))==cmap.end())
        {
          printf("Unknown col name %s in line %ld\n",
             name0.c_str(),lineno);
          errors=true;
        }
        else j=(citr->second).index;
// Assign non-basics
// Heuristic for assigning lp->x
// If finite lower bound use that value
// Else if finite upper bound use that value
// Otherwise use 0.0
       switch(type)
      {
         case LO: // Change lower bound from 0
            lp->nl[j] = value1;
            lp->x[j] = value1;
            lp->nrange[j] = ATLOWER;
            if(lp->ntype[j]== UBOUNDED||BOTHBOUNDS)
               lp->ntype[j]= BOTHBOUNDS;
            else
               lp->ntype[j] = LBOUNDED;
            break;
         case UP: // Add upper bound
            lp->nu[j] = value1;
            if(lp->ntype[j]== LBOUNDED||BOTHBOUNDS)
             lp->ntype[j]= BOTHBOUNDS;
            else
            {
               lp->ntype[j] = UBOUNDED;
               lp->x[j] = value1;
               lp->nrange[j] = ATUPPER;
            }
            break;
         case FX: // Make fixed
            lp->x[j] = lp->nu[j] = lp->nl[j] = value1;
            lp->ntype[j] = FIXED;
            lp->nrange[j] = ATBOTH;
            break;
         case FR: // Release both bounds
            lp->nu[j] = DBL_MAX;
            lp->nl[j] = -DBL_MAX;
            lp->x[j]=0;
            lp->nrange[j] = BETWEEN;
            lp->ntype[j] = FREE;
            break;
         case MI: // Release lower bound to - infinity
                  // Upper bound is zero unless set to
                  // Something else using UP
            lp->nl[j] = -DBL_MAX;
            lp->ntype[j] = UBOUNDED;
            lp->nrange[j] = ATUPPER;
            if(lp->nu[j] == DBL_MAX)
            {
               lp->x[j] = 0.0;
               lp->nrange[j] = BETWEEN;
               lp->ntype[j] = FREE;
           }
            else
            {
               lp->x[j] = lp->nu[j];
            }
            break;
         case PL: // Release upper bound to + infinity
                  // Lower bound is zero unless set to
                  // Something else using LO
            lp->nu[j] = DBL_MAX;
            lp->ntype[j] = LBOUNDED;
            lp->nrange[j] = ATLOWER;
            if(lp->nl[j] == -DBL_MAX)
            {
               lp->x[j] =  0.0;
               lp->nrange[j] = BETWEEN;
               lp->ntype[j] = FREE;
           }
            else
            {
               lp->x[j] = lp->nl[j];
            }
            break;
         default:
            printf("\nImproper type code");
            exit(306);
      }
    }
  return bytes;
}
//================ SCALE ================
// The scaling routine first scales the rows (excluding
// the objective) so that
// each row has a maximum absolute value of a coefficient
// equal to one. It then scales the columns so that each
// column has an maximum absolute value of one (excluding
// the right hand side. The
// bounds of the variables are adjusted to be consistent
// and the value to convert the objective back to its
// original units is returned (7/5/00)
double scale(long m, long n, double *rscale, double *cscale)
{
// Divide all the rows by the largest absolute value
// of its coefficients which have already been collected
// in the columns and rhs routines
   long i, j;
   for (i=1;i<=m;i++)
   {
     if(rscale[i] != 0.0)
     {
       double factor=1.0/rscale[i];
       for(j=0;j<=n;j++)lp->a[j][i]*=factor;
// Adjust bounds of basic variables
       if(((lp->btype[i])!=UBOUNDED)||((lp->btype[i])!=FREE))
         lp->bl[i]*=rscale[i];
       if((lp->ntype[i])!=LBOUNDED||(lp->btype[i])!=FREE)
         lp->bu[i]*=rscale[i];
     }
   }
// Scale the columns and save the factors
   for (j=1;j<=n;j++)
   {
     cscale[j]=0.0;
     for(i=1;i<=m;i++)
     {
       if(fabs(lp->a[j][i])>cscale[j])
         cscale[j]=fabs(lp->a[j][i]);
     }
   }
   for (j=1;j<=n;j++)
   {
     if(cscale[j]!=0.0)
     {
       double factor=1.0/cscale[j];
       for(i=0;i<=m;i++)lp->a[j][i]*=factor;
// Adjust the bounds of the non-basic variables
       if(lp->ntype[j]!=UBOUNDED||lp->ntype[j]!=FREE)
         lp->nl[j]*=cscale[j];
       if(lp->ntype[j]!=LBOUNDED||lp->ntype[j]!=FREE)
         lp->nu[j]*=cscale[j];
       lp->x[j]*=cscale[j];
     }
   }
#if DEBUG
  printf("ROW FACTORS: \n");
  for (i=0;i<m-1;i+=3)
    printf(" %5ld %10.4e %5ld %10.4e %5ld %10.4e \n",
      i,rscale[i],i,rscale[i+1],i,rscale[i+2]);
  if(((m+1)%3)==2)
    printf(" %5ld %10.4e %5ld %10.4e \n",
      m-1,rscale[m-1],m,rscale[m]);
  if(((m+1)%3)==1)
    printf(" %5ld %10.4e \n",
      m,rscale[m]);
  printf("COLUMN FACTORS: \n");
  for (j=0;j<n-1;j+=3)
    printf(" %5ld %10.4e %5ld %10.4e %5ld %10.4e \n",
      j,cscale[j],j,cscale[j+1],j,cscale[j+2]);
  if(((n+1)%3)==2)
    printf(" %5ld %10.4e %5ld %10.4e \n",
      n-1,rscale[n-1],n,rscale[n]);
  if(((n+1)%3)==1)
    printf(" %5ld %10.4e \n",
      n,rscale[n]);
#endif
  return rscale[0];
}
//================ PROBLEM_SIZE ================
// Makes first pass through input file to determine
// m (number of rows excluding Phase 1 and 2 objectives)
// n (number of columns excluding oonstant column); we
// also count the number of non-zero coefficients specified

void problem_size(FILE * file, long *pm, long *pn, long *pe)
{
std::string oldname;
std::string key, name0, name1, name2, buffer;
double value1, value2;
      long ncount=0;
short bytes;
long lineno=0; // Problem size gets its own local lineno; not global.
// Read NAME, title, ROWS
   if(NAME!=lparse(file, key, name0, name1, name2,
  value1, value2, buffer, lineno))
    {
      printf("NAME missing in input file\n");
      exit(6);
    }

   if(ROWS!=lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))
    {
      printf("Line: %ld; File not in MPS format;\
       expected ROWS key word\n", lineno );
      printf("Got: %s\n",buffer.c_str());
      exit(8);
    }
// Count rows
      while((bytes = lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))>7)
    {
      (*pm)++;
// Look for objective
      if(key.find_first_of("Nn")!=std::string::npos)ncount++;
    }
// If there is an objective subtract from m.
    if(ncount>0)(*pm)--;
// Check to see if Columns key word
   if(bytes!=COLUMNS)
    {
      printf("Line: %ld; File not in MPS format;\
       expected COLUMNS key word\n", lineno );
      printf("Got: %s\n",buffer.c_str());
      exit(8);
    }
    oldname="        ";

// Count columns and elements
      while((bytes = lparse(file, key, name0, name1, name2,
  value1, value2,buffer,lineno))>7)
    {
      if(name0!=oldname)

// New column
      {
        (*pn)++;
        oldname=name0;
      }
      if(bytes==13)*pe=*pe+2;
      if(bytes==11)(*pe)++;
    }
}

/************************************************************************
* retroLP solves linear programs using the simplex method.             *
* Copyright (C) 2001, 2003, 2005 Gavriel Yarmish & Richard Van Slyke.  *
*                                                                      *
* 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, Fifth Floor, Boston,           *
*                                                                      *
************************************************************************/
/*namespace makedll {
public ref class Fparse {
	short bounds2(FILE * file){
	return bounds(file);
	}
	LP_state *  fparse2( FILE *  file, long m, long n){
	return fparse(file,m,n);
	}
};}*/