source: trunk/Clp/src/ClpMain.cpp @ 799

Last change on this file since 799 was 799, checked in by andreasw, 14 years ago

undid last commit (patches incorrectly applied)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.3 KB
Line 
1// Copyright (C) 2002, International Business Machines
2// Corporation and others.  All Rights Reserved.
3   
4#include "CoinPragma.hpp"
5
6#include <cassert>
7#include <cstdio>
8#include <cmath>
9#include <cfloat>
10#include <string>
11#include <iostream>
12
13
14#include "CoinPragma.hpp"
15#include "CoinHelperFunctions.hpp"
16// History since 1.0 at end
17#define CLPVERSION "1.02.02"
18
19#include "CoinMpsIO.hpp"
20#include "CoinFileIO.hpp"
21
22#include "ClpFactorization.hpp"
23#include "CoinTime.hpp"
24#include "ClpSimplex.hpp"
25#include "ClpSimplexOther.hpp"
26#include "ClpSolve.hpp"
27#include "ClpPackedMatrix.hpp"
28#include "ClpPlusMinusOneMatrix.hpp"
29#include "ClpNetworkMatrix.hpp"
30#include "ClpDualRowSteepest.hpp"
31#include "ClpDualRowDantzig.hpp"
32#include "ClpLinearObjective.hpp"
33#include "ClpPrimalColumnSteepest.hpp"
34#include "ClpPrimalColumnDantzig.hpp"
35#include "ClpPresolve.hpp"
36#include "CbcOrClpParam.hpp"
37#ifdef DMALLOC
38#include "dmalloc.h"
39#endif
40#ifdef WSSMP_BARRIER
41#define FOREIGN_BARRIER
42#endif
43#ifdef UFL_BARRIER
44#define FOREIGN_BARRIER
45#endif
46#ifdef TAUCS_BARRIER
47#define FOREIGN_BARRIER
48#endif
49
50static double totalTime=0.0;
51static bool maskMatches(std::string & mask, std::string & check);
52
53//#############################################################################
54
55#ifdef NDEBUG
56#undef NDEBUG
57#endif
58
59int mainTest (int argc, const char *argv[],int algorithm,
60              ClpSimplex empty, bool doPresolve,int switchOff);
61static void statistics(ClpSimplex * originalModel, ClpSimplex * model);
62// Returns next valid field
63int CbcOrClpRead_mode=1;
64FILE * CbcOrClpReadCommand=stdin;
65int main (int argc, const char *argv[])
66{
67  // next {} is just to make sure all memory should be freed - for debug
68  {
69    double time1 = CoinCpuTime(),time2;
70    // Set up all non-standard stuff
71    //int numberModels=1;
72    ClpSimplex * models = new ClpSimplex[1];
73   
74    // default action on import
75    int allowImportErrors=0;
76    int keepImportNames=1;
77    int doIdiot=-1;
78    int outputFormat=2;
79    int slpValue=-1;
80    int printOptions=0;
81    int printMode=0;
82    int presolveOptions=0;
83    int doCrash=0;
84    int doSprint=-1;
85    // set reasonable defaults
86    int preSolve=5;
87    bool preSolveFile=false;
88    models->setPerturbation(50);
89    models->messageHandler()->setPrefix(false);
90    const char dirsep =  CoinFindDirSeparator();
91    std::string directory = (dirsep == '/' ? "./" : ".\\");
92    std::string defaultDirectory = directory;
93    std::string importFile ="";
94    std::string exportFile ="default.mps";
95    std::string importBasisFile ="";
96    int basisHasValues=0;
97    int substitution=3;
98    int dualize=0;
99    std::string exportBasisFile ="default.bas";
100    std::string saveFile ="default.prob";
101    std::string restoreFile ="default.prob";
102    std::string solutionFile ="stdout";
103    std::string solutionSaveFile ="solution.file";
104    std::string printMask="";
105    CbcOrClpParam parameters[CBCMAXPARAMETERS];
106    int numberParameters ;
107    establishParams(numberParameters,parameters) ;
108    parameters[whichParam(BASISIN,numberParameters,parameters)].setStringValue(importBasisFile);
109    parameters[whichParam(BASISOUT,numberParameters,parameters)].setStringValue(exportBasisFile);
110    parameters[whichParam(PRINTMASK,numberParameters,parameters)].setStringValue(printMask);
111    parameters[whichParam(DIRECTORY,numberParameters,parameters)].setStringValue(directory);
112    parameters[whichParam(DUALBOUND,numberParameters,parameters)].setDoubleValue(models->dualBound());
113    parameters[whichParam(DUALTOLERANCE,numberParameters,parameters)].setDoubleValue(models->dualTolerance());
114    parameters[whichParam(EXPORT,numberParameters,parameters)].setStringValue(exportFile);
115    parameters[whichParam(IDIOT,numberParameters,parameters)].setIntValue(doIdiot);
116    parameters[whichParam(IMPORT,numberParameters,parameters)].setStringValue(importFile);
117    parameters[whichParam(SOLVERLOGLEVEL,numberParameters,parameters)].setIntValue(models->logLevel());
118    parameters[whichParam(MAXFACTOR,numberParameters,parameters)].setIntValue(models->factorizationFrequency());
119    parameters[whichParam(MAXITERATION,numberParameters,parameters)].setIntValue(models->maximumIterations());
120    parameters[whichParam(OUTPUTFORMAT,numberParameters,parameters)].setIntValue(outputFormat);
121    parameters[whichParam(PRESOLVEPASS,numberParameters,parameters)].setIntValue(preSolve);
122    parameters[whichParam(PERTVALUE,numberParameters,parameters)].setIntValue(models->perturbation());
123    parameters[whichParam(PRIMALTOLERANCE,numberParameters,parameters)].setDoubleValue(models->primalTolerance());
124    parameters[whichParam(PRIMALWEIGHT,numberParameters,parameters)].setDoubleValue(models->infeasibilityCost());
125    parameters[whichParam(RESTORE,numberParameters,parameters)].setStringValue(restoreFile);
126    parameters[whichParam(SAVE,numberParameters,parameters)].setStringValue(saveFile);
127    parameters[whichParam(TIMELIMIT,numberParameters,parameters)].setDoubleValue(models->maximumSeconds());
128    parameters[whichParam(SOLUTION,numberParameters,parameters)].setStringValue(solutionFile);
129    parameters[whichParam(SAVESOL,numberParameters,parameters)].setStringValue(solutionSaveFile);
130    parameters[whichParam(SPRINT,numberParameters,parameters)].setIntValue(doSprint);
131    parameters[whichParam(SUBSTITUTION,numberParameters,parameters)].setIntValue(substitution);
132    parameters[whichParam(DUALIZE,numberParameters,parameters)].setIntValue(dualize);
133    parameters[whichParam(PRESOLVETOLERANCE,numberParameters,parameters)].setDoubleValue(1.0e-8);
134    int verbose=0;
135   
136    // total number of commands read
137    int numberGoodCommands=0;
138    bool * goodModels = new bool[1];
139
140    // Hidden stuff for barrier
141    int choleskyType = 0;
142    int gamma=0;
143    int scaleBarrier=0;
144    int doKKT=0;
145    int crossover=2; // do crossover unless quadratic
146   
147    int iModel=0;
148    goodModels[0]=false;
149    //models[0].scaling(1);
150    //models[0].setDualBound(1.0e6);
151    //models[0].setDualTolerance(1.0e-7);
152    //ClpDualRowSteepest steep;
153    //models[0].setDualRowPivotAlgorithm(steep);
154    //models[0].setPrimalTolerance(1.0e-7);
155    //ClpPrimalColumnSteepest steepP;
156    //models[0].setPrimalColumnPivotAlgorithm(steepP);
157    std::string field;
158    std::cout<<"Coin LP version "<<CLPVERSION
159             <<", build "<<__DATE__<<std::endl;
160    // Print command line
161    if (argc>1) {
162      printf("command line - ");
163      for (int i=0;i<argc;i++)
164        printf("%s ",argv[i]);
165      printf("\n");
166    }
167   
168    while (1) {
169      // next command
170      field=CoinReadGetCommand(argc,argv);
171     
172      // exit if null or similar
173      if (!field.length()) {
174        if (numberGoodCommands==1&&goodModels[0]) {
175          // we just had file name - do dual or primal
176          field="either";
177        } else if (!numberGoodCommands) {
178          // let's give the sucker a hint
179          std::cout
180            <<"Clp takes input from arguments ( - switches to stdin)"
181            <<std::endl
182            <<"Enter ? for list of commands or help"<<std::endl;
183          field="-";
184        } else {
185          break;
186        }
187      }
188     
189      // see if ? at end
190      int numberQuery=0;
191      if (field!="?"&&field!="???") {
192        int length = field.length();
193        int i;
194        for (i=length-1;i>0;i--) {
195          if (field[i]=='?') 
196            numberQuery++;
197          else
198            break;
199        }
200        field=field.substr(0,length-numberQuery);
201      }
202      // find out if valid command
203      int iParam;
204      int numberMatches=0;
205      int firstMatch=-1;
206      for ( iParam=0; iParam<numberParameters; iParam++ ) {
207        int match = parameters[iParam].matches(field);
208        if (match==1) {
209          numberMatches = 1;
210          firstMatch=iParam;
211          break;
212        } else {
213          if (match&&firstMatch<0)
214            firstMatch=iParam;
215          numberMatches += match>>1;
216        }
217      }
218      if (iParam<numberParameters&&!numberQuery) {
219        // found
220        CbcOrClpParam found = parameters[iParam];
221        CbcOrClpParameterType type = found.type();
222        int valid;
223        numberGoodCommands++;
224        if (type==GENERALQUERY) {
225          std::cout<<"In argument list keywords have leading - "
226            ", -stdin or just - switches to stdin"<<std::endl;
227          std::cout<<"One command per line (and no -)"<<std::endl;
228          std::cout<<"abcd? gives list of possibilities, if only one + explanation"<<std::endl;
229          std::cout<<"abcd?? adds explanation, if only one fuller help"<<std::endl;
230          std::cout<<"abcd without value (where expected) gives current value"<<std::endl;
231          std::cout<<"abcd value sets value"<<std::endl;
232          std::cout<<"Commands are:"<<std::endl;
233          int maxAcross=5;
234          if (verbose)
235            maxAcross=1;
236          int limits[]={1,101,201,301,401};
237          std::vector<std::string> types;
238          types.push_back("Double parameters:");
239          types.push_back("Int parameters:");
240          types.push_back("Keyword parameters:");
241          types.push_back("Actions or string parameters:");
242          int iType;
243          for (iType=0;iType<4;iType++) {
244            int across=0;
245            if ((verbose%4)!=0)
246              std::cout<<std::endl;
247            std::cout<<types[iType]<<std::endl;
248            if ((verbose&2)!=0)
249              std::cout<<std::endl;
250            for ( iParam=0; iParam<numberParameters; iParam++ ) {
251              int type = parameters[iParam].type();
252              if (parameters[iParam].displayThis()&&type>=limits[iType]
253                  &&type<limits[iType+1]) {
254                if (!across) {
255                  if ((verbose&2)==0) 
256                    std::cout<<"  ";
257                  else
258                    std::cout<<"Command ";
259                }
260                std::cout<<parameters[iParam].matchName()<<"  ";
261                across++;
262                if (across==maxAcross) {
263                  across=0;
264                  if (verbose) {
265                    // put out description as well
266                    if ((verbose&1)!=0) 
267                      std::cout<<parameters[iParam].shortHelp();
268                    std::cout<<std::endl;
269                    if ((verbose&2)!=0) {
270                      std::cout<<"---- description"<<std::endl;
271                      parameters[iParam].printLongHelp();
272                      std::cout<<"----"<<std::endl<<std::endl;
273                    }
274                  } else {
275                    std::cout<<std::endl;
276                  }
277                }
278              }
279            }
280            if (across)
281              std::cout<<std::endl;
282          }
283        } else if (type==FULLGENERALQUERY) {
284          std::cout<<"Full list of commands is:"<<std::endl;
285          int maxAcross=5;
286          int limits[]={1,101,201,301,401};
287          std::vector<std::string> types;
288          types.push_back("Double parameters:");
289          types.push_back("Int parameters:");
290          types.push_back("Keyword parameters and others:");
291          types.push_back("Actions:");
292          int iType;
293          for (iType=0;iType<4;iType++) {
294            int across=0;
295            std::cout<<types[iType]<<std::endl;
296            for ( iParam=0; iParam<numberParameters; iParam++ ) {
297              int type = parameters[iParam].type();
298              if (type>=limits[iType]
299                  &&type<limits[iType+1]) {
300                if (!across)
301                  std::cout<<"  ";
302                std::cout<<parameters[iParam].matchName()<<"  ";
303                across++;
304                if (across==maxAcross) {
305                  std::cout<<std::endl;
306                  across=0;
307                }
308              }
309            }
310            if (across)
311              std::cout<<std::endl;
312          }
313        } else if (type<101) {
314          // get next field as double
315          double value = CoinReadGetDoubleField(argc,argv,&valid);
316          if (!valid) {
317            parameters[iParam].setDoubleParameter(models+iModel,value);
318          } else if (valid==1) {
319            abort();
320          } else {
321            std::cout<<parameters[iParam].name()<<" has value "<<
322              parameters[iParam].doubleValue()<<std::endl;
323          }
324        } else if (type<201) {
325          // get next field as int
326          int value = CoinReadGetIntField(argc,argv,&valid);
327          if (!valid) {
328            if (parameters[iParam].type()==PRESOLVEPASS)
329              preSolve = value;
330            else if (parameters[iParam].type()==IDIOT)
331              doIdiot = value;
332            else if (parameters[iParam].type()==SPRINT)
333              doSprint = value;
334            else if (parameters[iParam].type()==OUTPUTFORMAT)
335              outputFormat = value;
336            else if (parameters[iParam].type()==SLPVALUE)
337              slpValue = value;
338            else if (parameters[iParam].type()==PRESOLVEOPTIONS)
339              presolveOptions = value;
340            else if (parameters[iParam].type()==PRINTOPTIONS)
341              printOptions = value;
342            else if (parameters[iParam].type()==SUBSTITUTION)
343              substitution = value;
344            else if (parameters[iParam].type()==DUALIZE)
345              dualize = value;
346            else if (parameters[iParam].type()==VERBOSE)
347              verbose = value;
348            parameters[iParam].setIntParameter(models+iModel,value);
349          } else if (valid==1) {
350            abort();
351          } else {
352            std::cout<<parameters[iParam].name()<<" has value "<<
353              parameters[iParam].intValue()<<std::endl;
354          }
355        } else if (type<301) {
356          // one of several strings
357          std::string value = CoinReadGetString(argc,argv);
358          int action = parameters[iParam].parameterOption(value);
359          if (action<0) {
360            if (value!="EOL") {
361              // no match
362              parameters[iParam].printOptions();
363            } else {
364              // print current value
365              std::cout<<parameters[iParam].name()<<" has value "<<
366                parameters[iParam].currentOption()<<std::endl;
367            }
368          } else {
369            parameters[iParam].setCurrentOption(action);
370            // for now hard wired
371            switch (type) {
372            case DIRECTION:
373              if (action==0)
374                models[iModel].setOptimizationDirection(1);
375              else if (action==1)
376                models[iModel].setOptimizationDirection(-1);
377              else
378                models[iModel].setOptimizationDirection(0);
379              break;
380            case DUALPIVOT:
381              if (action==0) {
382                ClpDualRowSteepest steep(3);
383                models[iModel].setDualRowPivotAlgorithm(steep);
384              } else if (action==1) {
385                //ClpDualRowDantzig dantzig;
386                ClpDualRowSteepest dantzig(5);
387                models[iModel].setDualRowPivotAlgorithm(dantzig);
388              } else if (action==2) {
389                // partial steep
390                ClpDualRowSteepest steep(2);
391                models[iModel].setDualRowPivotAlgorithm(steep);
392              } else {
393                ClpDualRowSteepest steep;
394                models[iModel].setDualRowPivotAlgorithm(steep);
395              }
396              break;
397            case PRIMALPIVOT:
398              if (action==0) {
399                ClpPrimalColumnSteepest steep(3);
400                models[iModel].setPrimalColumnPivotAlgorithm(steep);
401              } else if (action==1) {
402                ClpPrimalColumnSteepest steep(0);
403                models[iModel].setPrimalColumnPivotAlgorithm(steep);
404              } else if (action==2) {
405                ClpPrimalColumnDantzig dantzig;
406                models[iModel].setPrimalColumnPivotAlgorithm(dantzig);
407              } else if (action==3) {
408                ClpPrimalColumnSteepest steep(2);
409                models[iModel].setPrimalColumnPivotAlgorithm(steep);
410              } else if (action==4) {
411                ClpPrimalColumnSteepest steep(1);
412                models[iModel].setPrimalColumnPivotAlgorithm(steep);
413              } else if (action==5) {
414                ClpPrimalColumnSteepest steep(4);
415                models[iModel].setPrimalColumnPivotAlgorithm(steep);
416              } else if (action==6) {
417                ClpPrimalColumnSteepest steep(10);
418                models[iModel].setPrimalColumnPivotAlgorithm(steep);
419              }
420              break;
421            case SCALING:
422              models[iModel].scaling(action);
423              break;
424            case AUTOSCALE:
425              models[iModel].setAutomaticScaling(action!=0);
426              break;
427            case SPARSEFACTOR:
428              models[iModel].setSparseFactorization((1-action)!=0);
429              break;
430            case BIASLU:
431              models[iModel].factorization()->setBiasLU(action);
432              break;
433            case PERTURBATION:
434              if (action==0)
435                models[iModel].setPerturbation(50);
436              else
437                models[iModel].setPerturbation(100);
438              break;
439            case ERRORSALLOWED:
440              allowImportErrors = action;
441              break;
442            case INTPRINT:
443              printMode=action;
444              break;
445            case KEEPNAMES:
446              keepImportNames = 1-action;
447              break;
448            case PRESOLVE:
449              if (action==0)
450                preSolve = 5;
451              else if (action==1)
452                preSolve=0;
453              else if (action==2)
454                preSolve=10;
455              else
456                preSolveFile=true;
457              break;
458            case PFI:
459              models[iModel].factorization()->setForrestTomlin(action==0);
460              break;
461            case CRASH:
462              doCrash=action;
463              break;
464            case MESSAGES:
465              models[iModel].messageHandler()->setPrefix(action!=0);
466              break;
467            case CHOLESKY:
468              choleskyType = action;
469              break;
470            case GAMMA:
471              gamma=action;
472              break;
473            case BARRIERSCALE:
474              scaleBarrier=action;
475              break;
476            case KKT:
477              doKKT=action;
478              break;
479            case CROSSOVER:
480              crossover=action;
481              break;
482            default:
483              abort();
484            }
485          }
486        } else {
487          // action
488          if (type==EXIT)
489            break; // stop all
490          switch (type) {
491          case DUALSIMPLEX:
492          case PRIMALSIMPLEX:
493          case EITHERSIMPLEX:
494          case BARRIER:
495            // synonym for dual
496          case BAB:
497            if (goodModels[iModel]) {
498              double objScale = 
499                parameters[whichParam(OBJSCALE2,numberParameters,parameters)].doubleValue();
500              if (objScale!=1.0) {
501                int iColumn;
502                int numberColumns=models[iModel].numberColumns();
503                double * dualColumnSolution = 
504                  models[iModel].dualColumnSolution();
505                ClpObjective * obj = models[iModel].objectiveAsObject();
506                assert(dynamic_cast<ClpLinearObjective *> (obj));
507                double offset;
508                double * objective = obj->gradient(NULL,NULL,offset,true);
509                for (iColumn=0;iColumn<numberColumns;iColumn++) {
510                  dualColumnSolution[iColumn] *= objScale;
511                  objective[iColumn] *= objScale;;
512                }
513                int iRow;
514                int numberRows=models[iModel].numberRows();
515                double * dualRowSolution = 
516                  models[iModel].dualRowSolution();
517                for (iRow=0;iRow<numberRows;iRow++) 
518                  dualRowSolution[iRow] *= objScale;
519                models[iModel].setObjectiveOffset(objScale*models[iModel].objectiveOffset());
520              }
521              ClpSolve::SolveType method;
522              ClpSolve::PresolveType presolveType;
523              ClpSimplex * model2 = models+iModel;
524              if (dualize) {
525                model2 = ((ClpSimplexOther *) model2)->dualOfModel();
526                printf("Dual of model has %d rows and %d columns\n",
527                       model2->numberRows(),model2->numberColumns());
528                model2->setOptimizationDirection(1.0);
529              }
530              ClpSolve solveOptions;
531              solveOptions.setPresolveActions(presolveOptions);
532              solveOptions.setSubstitution(substitution);
533              if (preSolve!=5&&preSolve) {
534                presolveType=ClpSolve::presolveNumber;
535                if (preSolve<0) {
536                  preSolve = - preSolve;
537                  if (preSolve<=100) {
538                    presolveType=ClpSolve::presolveNumber;
539                    printf("Doing %d presolve passes - picking up non-costed slacks\n",
540                           preSolve);
541                    solveOptions.setDoSingletonColumn(true);
542                  } else {
543                    preSolve -=100;
544                    presolveType=ClpSolve::presolveNumberCost;
545                    printf("Doing %d presolve passes - picking up costed slacks\n",
546                           preSolve);
547                  }
548                } 
549              } else if (preSolve) {
550                presolveType=ClpSolve::presolveOn;
551              } else {
552                presolveType=ClpSolve::presolveOff;
553              }
554              solveOptions.setPresolveType(presolveType,preSolve);
555              if (type==DUALSIMPLEX||type==BAB) {
556                method=ClpSolve::useDual;
557              } else if (type==PRIMALSIMPLEX) {
558                method=ClpSolve::usePrimalorSprint;
559              } else if (type==EITHERSIMPLEX) {
560                method=ClpSolve::automatic;
561              } else {
562                method = ClpSolve::useBarrier;
563                if (crossover==1) {
564                  method=ClpSolve::useBarrierNoCross;
565                } else if (crossover==2) {
566                  ClpObjective * obj = models[iModel].objectiveAsObject();
567                  if (obj->type()>1) {
568                    method=ClpSolve::useBarrierNoCross;
569                    presolveType=ClpSolve::presolveOff;
570                    solveOptions.setPresolveType(presolveType,preSolve);
571                  } 
572                }
573              }
574              solveOptions.setSolveType(method);
575              if(preSolveFile)
576                presolveOptions |= 0x40000000;
577              solveOptions.setSpecialOption(4,presolveOptions);
578              solveOptions.setSpecialOption(5,printOptions&1);
579              if (method==ClpSolve::useDual) {
580                // dual
581                if (doCrash)
582                  solveOptions.setSpecialOption(0,1,doCrash); // crash
583                else if (doIdiot)
584                  solveOptions.setSpecialOption(0,2,doIdiot); // possible idiot
585              } else if (method==ClpSolve::usePrimalorSprint) {
586                // primal
587                // if slp turn everything off
588                if (slpValue>0) {
589                  doCrash=false;
590                  doSprint=0;
591                  doIdiot=-1;
592                  solveOptions.setSpecialOption(1,10,slpValue); // slp
593                  method=ClpSolve::usePrimal;
594                }
595                if (doCrash) {
596                  solveOptions.setSpecialOption(1,1,doCrash); // crash
597                } else if (doSprint>0) {
598                  // sprint overrides idiot
599                  solveOptions.setSpecialOption(1,3,doSprint); // sprint
600                } else if (doIdiot>0) {
601                  solveOptions.setSpecialOption(1,2,doIdiot); // idiot
602                } else if (slpValue<=0) {
603                  if (doIdiot==0) {
604                    if (doSprint==0)
605                      solveOptions.setSpecialOption(1,4); // all slack
606                    else
607                      solveOptions.setSpecialOption(1,9); // all slack or sprint
608                  } else {
609                    if (doSprint==0)
610                      solveOptions.setSpecialOption(1,8); // all slack or idiot
611                    else
612                      solveOptions.setSpecialOption(1,7); // initiative
613                  }
614                }
615                if (basisHasValues==-1)
616                  solveOptions.setSpecialOption(1,11); // switch off values
617              } else if (method==ClpSolve::useBarrier||method==ClpSolve::useBarrierNoCross) {
618                int barrierOptions = choleskyType;
619                if (scaleBarrier)
620                  barrierOptions |= 8;
621                if (doKKT)
622                  barrierOptions |= 16;
623                if (gamma)
624                  barrierOptions |= 32*gamma;
625                if (crossover==3) 
626                  barrierOptions |= 256; // try presolve in crossover
627                solveOptions.setSpecialOption(4,barrierOptions);
628              }
629              int status;
630              try {
631                status=model2->initialSolve(solveOptions);
632              }
633              catch (CoinError e) {
634                e.print();
635                status=-1;
636              }
637              if (dualize) {
638                ((ClpSimplexOther *) models+iModel)->restoreFromDual(model2);
639                delete model2;
640              }
641              if (status>=0)
642                basisHasValues=1;
643            } else {
644              std::cout<<"** Current model not valid"<<std::endl;
645            }
646            break;
647          case STATISTICS:
648            if (goodModels[iModel]) {
649              // If presolve on look at presolved
650              bool deleteModel2=false;
651              ClpSimplex * model2 = models+iModel;
652              if (preSolve) {
653                ClpPresolve pinfo;
654                int presolveOptions2 = presolveOptions&~0x40000000;
655                if ((presolveOptions2&0xffff)!=0)
656                  pinfo.setPresolveActions(presolveOptions2);
657                pinfo.setSubstitution(substitution);
658                if ((printOptions&1)!=0)
659                  pinfo.statistics();
660                double presolveTolerance = 
661                  parameters[whichParam(PRESOLVETOLERANCE,numberParameters,parameters)].doubleValue();
662                model2 = 
663                  pinfo.presolvedModel(models[iModel],presolveTolerance,
664                                       true,preSolve);
665                if (model2) {
666                  printf("Statistics for presolved model\n");
667                  deleteModel2=true;
668                } else {
669                  printf("Presolved model looks infeasible - will use unpresolved\n");
670                  model2 = models+iModel;
671                }
672              } else {
673                printf("Statistics for unpresolved model\n");
674                model2 =  models+iModel;
675              }
676              statistics(models+iModel,model2);
677              if (deleteModel2)
678                delete model2;
679            } else {
680              std::cout<<"** Current model not valid"<<std::endl;
681            }
682            break;
683          case TIGHTEN:
684            if (goodModels[iModel]) {
685              int numberInfeasibilities = models[iModel].tightenPrimalBounds();
686              if (numberInfeasibilities)
687                std::cout<<"** Analysis indicates model infeasible"<<std::endl;
688            } else {
689              std::cout<<"** Current model not valid"<<std::endl;
690            }
691            break;
692          case PLUSMINUS:
693            if (goodModels[iModel]) {
694              ClpMatrixBase * saveMatrix = models[iModel].clpMatrix();
695              ClpPackedMatrix* clpMatrix =
696                dynamic_cast< ClpPackedMatrix*>(saveMatrix);
697              if (clpMatrix) {
698                ClpPlusMinusOneMatrix * newMatrix = new ClpPlusMinusOneMatrix(*(clpMatrix->matrix()));
699                if (newMatrix->getIndices()) {
700                  models[iModel].replaceMatrix(newMatrix);
701                  delete saveMatrix;
702                  std::cout<<"Matrix converted to +- one matrix"<<std::endl;
703                } else {
704                  std::cout<<"Matrix can not be converted to +- 1 matrix"<<std::endl;
705                }
706              } else {
707                std::cout<<"Matrix not a ClpPackedMatrix"<<std::endl;
708              }
709            } else {
710              std::cout<<"** Current model not valid"<<std::endl;
711            }
712            break;
713          case NETWORK:
714            if (goodModels[iModel]) {
715              ClpMatrixBase * saveMatrix = models[iModel].clpMatrix();
716              ClpPackedMatrix* clpMatrix =
717                dynamic_cast< ClpPackedMatrix*>(saveMatrix);
718              if (clpMatrix) {
719                ClpNetworkMatrix * newMatrix = new ClpNetworkMatrix(*(clpMatrix->matrix()));
720                if (newMatrix->getIndices()) {
721                  models[iModel].replaceMatrix(newMatrix);
722                  delete saveMatrix;
723                  std::cout<<"Matrix converted to network matrix"<<std::endl;
724                } else {
725                  std::cout<<"Matrix can not be converted to network matrix"<<std::endl;
726                }
727              } else {
728                std::cout<<"Matrix not a ClpPackedMatrix"<<std::endl;
729              }
730            } else {
731              std::cout<<"** Current model not valid"<<std::endl;
732            }
733            break;
734          case IMPORT:
735            {
736              // get next field
737              field = CoinReadGetString(argc,argv);
738              if (field=="$") {
739                field = parameters[iParam].stringValue();
740              } else if (field=="EOL") {
741                parameters[iParam].printString();
742                break;
743              } else {
744                parameters[iParam].setStringValue(field);
745              }
746              std::string fileName;
747              bool canOpen=false;
748              // See if gmpl file
749              int gmpl=0;
750              std::string gmplData;
751              if (field=="-") {
752                // stdin
753                canOpen=true;
754                fileName = "-";
755              } else {
756                bool absolutePath;
757                if (dirsep=='/') {
758                  // non Windows (or cygwin)
759                  absolutePath=(field[0]=='/');
760                } else {
761                  //Windows (non cycgwin)
762                  absolutePath=(field[0]=='\\');
763                  // but allow for :
764                  if (strchr(field.c_str(),':'))
765                    absolutePath=true;
766                }
767                if (absolutePath) {
768                  fileName = field;
769                } else if (field[0]=='~') {
770                  char * environVar = getenv("HOME");
771                  if (environVar) {
772                    std::string home(environVar);
773                    field=field.erase(0,1);
774                    fileName = home+field;
775                  } else {
776                    fileName=field;
777                  }
778                } else {
779                  fileName = directory+field;
780                  // See if gmpl (model & data)
781                  int length = field.size();
782                  int percent = field.find('%');
783                  if (percent<length&&percent>0) {
784                    gmpl=1;
785                    fileName = directory+field.substr(0,percent);
786                    gmplData = directory+field.substr(percent+1);
787                    if (percent<length-1)
788                      gmpl=2; // two files
789                    printf("GMPL model file %s and data file %s\n",
790                           fileName.c_str(),gmplData.c_str());
791                  }
792                }
793                std::string name=fileName;
794                if (fileCoinReadable(name)) {
795                  // can open - lets go for it
796                  canOpen=true;
797                  if (gmpl==2) {
798                    FILE *fp;
799                    fp=fopen(gmplData.c_str(),"r");
800                    if (fp) {
801                      fclose(fp);
802                    } else {
803                      canOpen=false;
804                      std::cout<<"Unable to open file "<<gmplData<<std::endl;
805                    }
806                  }
807                } else {
808                  std::cout<<"Unable to open file "<<fileName<<std::endl;
809                }
810              }
811              if (canOpen) {
812                int status;
813                if (!gmpl)
814                  status =models[iModel].readMps(fileName.c_str(),
815                                                 keepImportNames!=0,
816                                                 allowImportErrors!=0);
817                else
818                  status= models[iModel].readGMPL(fileName.c_str(),
819                                                  (gmpl==2) ? gmplData.c_str() : NULL,
820                                                  keepImportNames!=0);
821                if (!status||(status>0&&allowImportErrors)) {
822                  goodModels[iModel]=true;
823                  // sets to all slack (not necessary?)
824                  models[iModel].createStatus();
825                  time2 = CoinCpuTime();
826                  totalTime += time2-time1;
827                  time1=time2;
828                  // Go to canned file if just input file
829                  if (CbcOrClpRead_mode==2&&argc==2) {
830                    // only if ends .mps
831                    char * find = (char *)strstr(fileName.c_str(),".mps");
832                    if (find&&find[4]=='\0') {
833                      find[1]='p'; find[2]='a';find[3]='r';
834                      FILE *fp=fopen(fileName.c_str(),"r");
835                      if (fp) {
836                        CbcOrClpReadCommand=fp; // Read from that file
837                        CbcOrClpRead_mode=-1;
838                      }
839                    }
840                  }
841                } else {
842                  // errors
843                  std::cout<<"There were "<<status<<
844                    " errors on input"<<std::endl;
845                }
846              }
847            }
848            break;
849          case EXPORT:
850            if (goodModels[iModel]) {
851              double objScale = 
852                parameters[whichParam(OBJSCALE2,numberParameters,parameters)].doubleValue();
853              if (objScale!=1.0) {
854                int iColumn;
855                int numberColumns=models[iModel].numberColumns();
856                double * dualColumnSolution = 
857                  models[iModel].dualColumnSolution();
858                ClpObjective * obj = models[iModel].objectiveAsObject();
859                assert(dynamic_cast<ClpLinearObjective *> (obj));
860                double offset;
861                double * objective = obj->gradient(NULL,NULL,offset,true);
862                for (iColumn=0;iColumn<numberColumns;iColumn++) {
863                  dualColumnSolution[iColumn] *= objScale;
864                  objective[iColumn] *= objScale;;
865                }
866                int iRow;
867                int numberRows=models[iModel].numberRows();
868                double * dualRowSolution = 
869                  models[iModel].dualRowSolution();
870                for (iRow=0;iRow<numberRows;iRow++) 
871                  dualRowSolution[iRow] *= objScale;
872                models[iModel].setObjectiveOffset(objScale*models[iModel].objectiveOffset());
873              }
874              // get next field
875              field = CoinReadGetString(argc,argv);
876              if (field=="$") {
877                field = parameters[iParam].stringValue();
878              } else if (field=="EOL") {
879                parameters[iParam].printString();
880                break;
881              } else {
882                parameters[iParam].setStringValue(field);
883              }
884              std::string fileName;
885              bool canOpen=false;
886              if (field[0]=='/'||field[0]=='\\') {
887                fileName = field;
888              } else if (field[0]=='~') {
889                char * environVar = getenv("HOME");
890                if (environVar) {
891                  std::string home(environVar);
892                  field=field.erase(0,1);
893                  fileName = home+field;
894                } else {
895                  fileName=field;
896                }
897              } else {
898                fileName = directory+field;
899              }
900              FILE *fp=fopen(fileName.c_str(),"w");
901              if (fp) {
902                // can open - lets go for it
903                fclose(fp);
904                canOpen=true;
905              } else {
906                std::cout<<"Unable to open file "<<fileName<<std::endl;
907              }
908              if (canOpen) {
909                // If presolve on then save presolved
910                bool deleteModel2=false;
911                ClpSimplex * model2 = models+iModel;
912                if (preSolve) {
913                  ClpPresolve pinfo;
914                  int presolveOptions2 = presolveOptions&~0x40000000;
915                  if ((presolveOptions2&0xffff)!=0)
916                    pinfo.setPresolveActions(presolveOptions2);
917                  pinfo.setSubstitution(substitution);
918                  if ((printOptions&1)!=0)
919                    pinfo.statistics();
920                  double presolveTolerance = 
921                    parameters[whichParam(PRESOLVETOLERANCE,numberParameters,parameters)].doubleValue();
922                  model2 = 
923                    pinfo.presolvedModel(models[iModel],presolveTolerance,
924                                         true,preSolve,false,false);
925                  if (model2) {
926                    printf("Saving presolved model on %s\n",
927                           fileName.c_str());
928                    deleteModel2=true;
929                  } else {
930                    printf("Presolved model looks infeasible - saving original on %s\n",
931                           fileName.c_str());
932                    deleteModel2=false;
933                    model2 = models+iModel;
934
935                  }
936                } else {
937                  printf("Saving model on %s\n",
938                           fileName.c_str());
939                }
940#if 0
941                // Convert names
942                int iRow;
943                int numberRows=model2->numberRows();
944                int iColumn;
945                int numberColumns=model2->numberColumns();
946
947                char ** rowNames = NULL;
948                char ** columnNames = NULL;
949                if (model2->lengthNames()) {
950                  rowNames = new char * [numberRows];
951                  for (iRow=0;iRow<numberRows;iRow++) {
952                    rowNames[iRow] =
953                      strdup(model2->rowName(iRow).c_str());
954#ifdef STRIPBLANKS
955                    char * xx = rowNames[iRow];
956                    int i;
957                    int length = strlen(xx);
958                    int n=0;
959                    for (i=0;i<length;i++) {
960                      if (xx[i]!=' ')
961                        xx[n++]=xx[i];
962                    }
963                    xx[n]='\0';
964#endif
965                  }
966                 
967                  columnNames = new char * [numberColumns];
968                  for (iColumn=0;iColumn<numberColumns;iColumn++) {
969                    columnNames[iColumn] =
970                      strdup(model2->columnName(iColumn).c_str());
971#ifdef STRIPBLANKS
972                    char * xx = columnNames[iColumn];
973                    int i;
974                    int length = strlen(xx);
975                    int n=0;
976                    for (i=0;i<length;i++) {
977                      if (xx[i]!=' ')
978                        xx[n++]=xx[i];
979                    }
980                    xx[n]='\0';
981#endif
982                  }
983                }
984                CoinMpsIO writer;
985                writer.setMpsData(*model2->matrix(), COIN_DBL_MAX,
986                                  model2->getColLower(), model2->getColUpper(),
987                                  model2->getObjCoefficients(),
988                                  (const char*) 0 /*integrality*/,
989                                  model2->getRowLower(), model2->getRowUpper(),
990                                  columnNames, rowNames);
991                // Pass in array saying if each variable integer
992                writer.copyInIntegerInformation(model2->integerInformation());
993                writer.setObjectiveOffset(model2->objectiveOffset());
994                writer.writeMps(fileName.c_str(),0,1,1);
995                if (rowNames) {
996                  for (iRow=0;iRow<numberRows;iRow++) {
997                    free(rowNames[iRow]);
998                  }
999                  delete [] rowNames;
1000                  for (iColumn=0;iColumn<numberColumns;iColumn++) {
1001                    free(columnNames[iColumn]);
1002                  }
1003                  delete [] columnNames;
1004                }
1005#else
1006                if (dualize) {
1007                  ClpSimplex * model3 = ((ClpSimplexOther *) model2)->dualOfModel();
1008                  printf("Dual of model has %d rows and %d columns\n",
1009                         model3->numberRows(),model3->numberColumns());
1010                  model3->writeMps(fileName.c_str(),(outputFormat-1)/2,1+((outputFormat-1)&1));
1011                  delete model3;
1012                } else {
1013                  model2->writeMps(fileName.c_str(),(outputFormat-1)/2,1+((outputFormat-1)&1));
1014                }
1015#endif
1016                if (deleteModel2)
1017                  delete model2;
1018                time2 = CoinCpuTime();
1019                totalTime += time2-time1;
1020                time1=time2;
1021              }
1022            } else {
1023              std::cout<<"** Current model not valid"<<std::endl;
1024            }
1025            break;
1026          case BASISIN:
1027            if (goodModels[iModel]) {
1028              // get next field
1029              field = CoinReadGetString(argc,argv);
1030              if (field=="$") {
1031                field = parameters[iParam].stringValue();
1032              } else if (field=="EOL") {
1033                parameters[iParam].printString();
1034                break;
1035              } else {
1036                parameters[iParam].setStringValue(field);
1037              }
1038              std::string fileName;
1039              bool canOpen=false;
1040              if (field=="-") {
1041                // stdin
1042                canOpen=true;
1043                fileName = "-";
1044              } else {
1045                if (field[0]=='/'||field[0]=='\\') {
1046                  fileName = field;
1047                } else if (field[0]=='~') {
1048                  char * environVar = getenv("HOME");
1049                  if (environVar) {
1050                    std::string home(environVar);
1051                    field=field.erase(0,1);
1052                    fileName = home+field;
1053                  } else {
1054                    fileName=field;
1055                  }
1056                } else {
1057                  fileName = directory+field;
1058                }
1059                FILE *fp=fopen(fileName.c_str(),"r");
1060                if (fp) {
1061                  // can open - lets go for it
1062                  fclose(fp);
1063                  canOpen=true;
1064                } else {
1065                  std::cout<<"Unable to open file "<<fileName<<std::endl;
1066                }
1067              }
1068              if (canOpen) {
1069                int values = models[iModel].readBasis(fileName.c_str());
1070                if (values==0)
1071                  basisHasValues=-1;
1072                else
1073                  basisHasValues=1;
1074              }
1075            } else {
1076              std::cout<<"** Current model not valid"<<std::endl;
1077            }
1078            break;
1079          case PRINTMASK:
1080            // get next field
1081            {
1082              std::string name = CoinReadGetString(argc,argv);
1083              if (name!="EOL") {
1084                parameters[iParam].setStringValue(name);
1085                printMask = name;
1086              } else {
1087                parameters[iParam].printString();
1088              }
1089            }
1090            break;
1091          case BASISOUT:
1092            if (goodModels[iModel]) {
1093              // get next field
1094              field = CoinReadGetString(argc,argv);
1095              if (field=="$") {
1096                field = parameters[iParam].stringValue();
1097              } else if (field=="EOL") {
1098                parameters[iParam].printString();
1099                break;
1100              } else {
1101                parameters[iParam].setStringValue(field);
1102              }
1103              std::string fileName;
1104              bool canOpen=false;
1105              if (field[0]=='/'||field[0]=='\\') {
1106                fileName = field;
1107              } else if (field[0]=='~') {
1108                char * environVar = getenv("HOME");
1109                if (environVar) {
1110                  std::string home(environVar);
1111                  field=field.erase(0,1);
1112                  fileName = home+field;
1113                } else {
1114                  fileName=field;
1115                }
1116              } else {
1117                fileName = directory+field;
1118              }
1119              FILE *fp=fopen(fileName.c_str(),"w");
1120              if (fp) {
1121                // can open - lets go for it
1122                fclose(fp);
1123                canOpen=true;
1124              } else {
1125                std::cout<<"Unable to open file "<<fileName<<std::endl;
1126              }
1127              if (canOpen) {
1128                ClpSimplex * model2 = models+iModel;
1129                model2->writeBasis(fileName.c_str(),outputFormat>1,outputFormat-2);
1130                time2 = CoinCpuTime();
1131                totalTime += time2-time1;
1132                time1=time2;
1133              }
1134            } else {
1135              std::cout<<"** Current model not valid"<<std::endl;
1136            }
1137            break;
1138          case SAVE:
1139            {
1140              // get next field
1141              field = CoinReadGetString(argc,argv);
1142              if (field=="$") {
1143                field = parameters[iParam].stringValue();
1144              } else if (field=="EOL") {
1145                parameters[iParam].printString();
1146                break;
1147              } else {
1148                parameters[iParam].setStringValue(field);
1149              }
1150              std::string fileName;
1151              bool canOpen=false;
1152              if (field[0]=='/'||field[0]=='\\') {
1153                fileName = field;
1154              } else if (field[0]=='~') {
1155                char * environVar = getenv("HOME");
1156                if (environVar) {
1157                  std::string home(environVar);
1158                  field=field.erase(0,1);
1159                  fileName = home+field;
1160                } else {
1161                  fileName=field;
1162                }
1163              } else {
1164                fileName = directory+field;
1165              }
1166              FILE *fp=fopen(fileName.c_str(),"wb");
1167              if (fp) {
1168                // can open - lets go for it
1169                fclose(fp);
1170                canOpen=true;
1171              } else {
1172                std::cout<<"Unable to open file "<<fileName<<std::endl;
1173              }
1174              if (canOpen) {
1175                int status;
1176                // If presolve on then save presolved
1177                bool deleteModel2=false;
1178                ClpSimplex * model2 = models+iModel;
1179                if (preSolve) {
1180                  ClpPresolve pinfo;
1181                  double presolveTolerance = 
1182                    parameters[whichParam(PRESOLVETOLERANCE,numberParameters,parameters)].doubleValue();
1183                  model2 = 
1184                    pinfo.presolvedModel(models[iModel],presolveTolerance,
1185                                         false,preSolve);
1186                  if (model2) {
1187                    printf("Saving presolved model on %s\n",
1188                           fileName.c_str());
1189                    deleteModel2=true;
1190                  } else {
1191                    printf("Presolved model looks infeasible - saving original on %s\n",
1192                           fileName.c_str());
1193                    deleteModel2=false;
1194                    model2 = models+iModel;
1195
1196                  }
1197                } else {
1198                  printf("Saving model on %s\n",
1199                           fileName.c_str());
1200                }
1201                status =model2->saveModel(fileName.c_str());
1202                if (deleteModel2)
1203                  delete model2;
1204                if (!status) {
1205                  goodModels[iModel]=true;
1206                  time2 = CoinCpuTime();
1207                  totalTime += time2-time1;
1208                  time1=time2;
1209                } else {
1210                  // errors
1211                  std::cout<<"There were errors on output"<<std::endl;
1212                }
1213              }
1214            }
1215            break;
1216          case RESTORE:
1217            {
1218              // get next field
1219              field = CoinReadGetString(argc,argv);
1220              if (field=="$") {
1221                field = parameters[iParam].stringValue();
1222              } else if (field=="EOL") {
1223                parameters[iParam].printString();
1224                break;
1225              } else {
1226                parameters[iParam].setStringValue(field);
1227              }
1228              std::string fileName;
1229              bool canOpen=false;
1230              if (field[0]=='/'||field[0]=='\\') {
1231                fileName = field;
1232              } else if (field[0]=='~') {
1233                char * environVar = getenv("HOME");
1234                if (environVar) {
1235                  std::string home(environVar);
1236                  field=field.erase(0,1);
1237                  fileName = home+field;
1238                } else {
1239                  fileName=field;
1240                }
1241              } else {
1242                fileName = directory+field;
1243              }
1244              FILE *fp=fopen(fileName.c_str(),"rb");
1245              if (fp) {
1246                // can open - lets go for it
1247                fclose(fp);
1248                canOpen=true;
1249              } else {
1250                std::cout<<"Unable to open file "<<fileName<<std::endl;
1251              }
1252              if (canOpen) {
1253                int status =models[iModel].restoreModel(fileName.c_str());
1254                if (!status) {
1255                  goodModels[iModel]=true;
1256                  time2 = CoinCpuTime();
1257                  totalTime += time2-time1;
1258                  time1=time2;
1259                } else {
1260                  // errors
1261                  std::cout<<"There were errors on input"<<std::endl;
1262                }
1263              }
1264            }
1265            break;
1266          case MAXIMIZE:
1267            models[iModel].setOptimizationDirection(-1);
1268            break;
1269          case MINIMIZE:
1270            models[iModel].setOptimizationDirection(1);
1271            break;
1272          case ALLSLACK:
1273            models[iModel].allSlackBasis(true);
1274            break;
1275          case REVERSE:
1276            if (goodModels[iModel]) {
1277              int iColumn;
1278              int numberColumns=models[iModel].numberColumns();
1279              double * dualColumnSolution = 
1280                models[iModel].dualColumnSolution();
1281              ClpObjective * obj = models[iModel].objectiveAsObject();
1282              assert(dynamic_cast<ClpLinearObjective *> (obj));
1283              double offset;
1284              double * objective = obj->gradient(NULL,NULL,offset,true);
1285              for (iColumn=0;iColumn<numberColumns;iColumn++) {
1286                dualColumnSolution[iColumn] = -dualColumnSolution[iColumn];
1287                objective[iColumn] = -objective[iColumn];
1288              }
1289              int iRow;
1290              int numberRows=models[iModel].numberRows();
1291              double * dualRowSolution = 
1292                models[iModel].dualRowSolution();
1293              for (iRow=0;iRow<numberRows;iRow++) 
1294                dualRowSolution[iRow] = -dualRowSolution[iRow];
1295              models[iModel].setObjectiveOffset(-models[iModel].objectiveOffset());
1296            }
1297            break;
1298          case DIRECTORY:
1299            {
1300              std::string name = CoinReadGetString(argc,argv);
1301              if (name!="EOL") {
1302                int length=name.length();
1303                if (name[length-1]=='/'||name[length-1]=='\\')
1304                  directory=name;
1305                else
1306                  directory = name+"/";
1307                parameters[iParam].setStringValue(directory);
1308              } else {
1309                parameters[iParam].printString();
1310              }
1311            }
1312            break;
1313          case STDIN:
1314            CbcOrClpRead_mode=-1;
1315            break;
1316          case NETLIB_DUAL:
1317          case NETLIB_EITHER:
1318          case NETLIB_BARRIER:
1319          case NETLIB_PRIMAL:
1320          case NETLIB_TUNE:
1321            {
1322              // create fields for unitTest
1323              const char * fields[4];
1324              int nFields=2;
1325              fields[0]="fake main from unitTest";
1326              fields[1]="-netlib";
1327              if (directory!=defaultDirectory) {
1328                fields[2]="-netlibDir";
1329                fields[3]=directory.c_str();
1330                nFields=4;
1331              }
1332              int algorithm;
1333              if (type==NETLIB_DUAL) {
1334                std::cerr<<"Doing netlib with dual algorithm"<<std::endl;
1335                algorithm =0;
1336              } else if (type==NETLIB_BARRIER) {
1337                std::cerr<<"Doing netlib with barrier algorithm"<<std::endl;
1338                algorithm =2;
1339              } else if (type==NETLIB_EITHER) {
1340                std::cerr<<"Doing netlib with dual or primal algorithm"<<std::endl;
1341                algorithm =3;
1342              } else if (type==NETLIB_TUNE) {
1343                std::cerr<<"Doing netlib with best algorithm!"<<std::endl;
1344                algorithm =5;
1345                // uncomment next to get active tuning
1346                // algorithm=6;
1347              } else {
1348                std::cerr<<"Doing netlib with primal agorithm"<<std::endl;
1349                algorithm=1;
1350              }
1351              int specialOptions = models[iModel].specialOptions();
1352              models[iModel].setSpecialOptions(0);
1353              mainTest(nFields,fields,algorithm,models[iModel],
1354                       (preSolve!=0),specialOptions);
1355            }
1356            break;
1357          case UNITTEST:
1358            {
1359              // create fields for unitTest
1360              const char * fields[3];
1361              int nFields=1;
1362              fields[0]="fake main from unitTest";
1363              if (directory!=defaultDirectory) {
1364                fields[1]="-mpsDir";
1365                fields[2]=directory.c_str();
1366                nFields=3;
1367              }
1368              int specialOptions = models[iModel].specialOptions();
1369              models[iModel].setSpecialOptions(0);
1370              int algorithm=-1;
1371              if (models[iModel].numberRows())
1372                algorithm=7;
1373              mainTest(nFields,fields,algorithm,models[iModel],(preSolve!=0),specialOptions);
1374            }
1375            break;
1376          case FAKEBOUND:
1377            if (goodModels[iModel]) {
1378              // get bound
1379              double value = CoinReadGetDoubleField(argc,argv,&valid);
1380              if (!valid) {
1381                std::cout<<"Setting "<<parameters[iParam].name()<<
1382                  " to DEBUG "<<value<<std::endl;
1383                int iRow;
1384                int numberRows=models[iModel].numberRows();
1385                double * rowLower = models[iModel].rowLower();
1386                double * rowUpper = models[iModel].rowUpper();
1387                for (iRow=0;iRow<numberRows;iRow++) {
1388                  // leave free ones for now
1389                  if (rowLower[iRow]>-1.0e20||rowUpper[iRow]<1.0e20) {
1390                    rowLower[iRow]=CoinMax(rowLower[iRow],-value);
1391                    rowUpper[iRow]=CoinMin(rowUpper[iRow],value);
1392                  }
1393                }
1394                int iColumn;
1395                int numberColumns=models[iModel].numberColumns();
1396                double * columnLower = models[iModel].columnLower();
1397                double * columnUpper = models[iModel].columnUpper();
1398                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1399                  // leave free ones for now
1400                  if (columnLower[iColumn]>-1.0e20||
1401                      columnUpper[iColumn]<1.0e20) {
1402                    columnLower[iColumn]=CoinMax(columnLower[iColumn],-value);
1403                    columnUpper[iColumn]=CoinMin(columnUpper[iColumn],value);
1404                  }
1405                }
1406              } else if (valid==1) {
1407                abort();
1408              } else {
1409                std::cout<<"enter value for "<<parameters[iParam].name()<<
1410                  std::endl;
1411              }
1412            }
1413            break;
1414          case REALLY_SCALE:
1415            if (goodModels[iModel]) {
1416              ClpSimplex newModel(models[iModel],
1417                                  models[iModel].scalingFlag());
1418              printf("model really really scaled\n");
1419              models[iModel]=newModel;
1420            }
1421            break;
1422          case HELP:
1423            std::cout<<"Coin LP version "<<CLPVERSION
1424                     <<", build "<<__DATE__<<std::endl;
1425            std::cout<<"Non default values:-"<<std::endl;
1426            std::cout<<"Perturbation "<<models[0].perturbation()<<" (default 100)"
1427                     <<std::endl;
1428            CoinReadPrintit(
1429                    "Presolve being done with 5 passes\n\
1430Dual steepest edge steep/partial on matrix shape and factorization density\n\
1431Clpnnnn taken out of messages\n\
1432If Factorization frequency default then done on size of matrix\n\n\
1433(-)unitTest, (-)netlib or (-)netlibp will do standard tests\n\n\
1434You can switch to interactive mode at any time so\n\
1435clp watson.mps -scaling off -primalsimplex\nis the same as\n\
1436clp watson.mps -\nscaling off\nprimalsimplex"
1437                    );
1438            break;
1439          case SOLUTION:
1440            if (goodModels[iModel]) {
1441              // get next field
1442              field = CoinReadGetString(argc,argv);
1443              if (field=="$") {
1444                field = parameters[iParam].stringValue();
1445              } else if (field=="EOL") {
1446                parameters[iParam].printString();
1447                break;
1448              } else {
1449                parameters[iParam].setStringValue(field);
1450              }
1451              std::string fileName;
1452              FILE *fp=NULL;
1453              if (field=="-"||field=="EOL"||field=="stdout") {
1454                // stdout
1455                fp=stdout;
1456                fprintf(fp,"\n");
1457              } else if (field=="stderr") {
1458                // stderr
1459                fp=stderr;
1460                fprintf(fp,"\n");
1461              } else {
1462                if (field[0]=='/'||field[0]=='\\') {
1463                  fileName = field;
1464                } else if (field[0]=='~') {
1465                  char * environVar = getenv("HOME");
1466                  if (environVar) {
1467                    std::string home(environVar);
1468                    field=field.erase(0,1);
1469                    fileName = home+field;
1470                  } else {
1471                    fileName=field;
1472                  }
1473                } else {
1474                  fileName = directory+field;
1475                }
1476                fp=fopen(fileName.c_str(),"w");
1477              }
1478              if (fp) {
1479                // make fancy later on
1480                int iRow;
1481                int numberRows=models[iModel].numberRows();
1482                int lengthName = models[iModel].lengthNames(); // 0 if no names
1483                // in general I don't want to pass around massive
1484                // amounts of data but seems simpler here
1485                std::vector<std::string> rowNames =
1486                  *(models[iModel].rowNames());
1487                std::vector<std::string> columnNames =
1488                  *(models[iModel].columnNames());
1489
1490                double * dualRowSolution = models[iModel].dualRowSolution();
1491                double * primalRowSolution = 
1492                  models[iModel].primalRowSolution();
1493                double * rowLower = models[iModel].rowLower();
1494                double * rowUpper = models[iModel].rowUpper();
1495                double primalTolerance = models[iModel].primalTolerance();
1496                char format[6];
1497                sprintf(format,"%%-%ds",CoinMax(lengthName,8));
1498                bool doMask = (printMask!=""&&lengthName);
1499                if (printMode>2) {
1500                  for (iRow=0;iRow<numberRows;iRow++) {
1501                    int type=printMode-3;
1502                    if (primalRowSolution[iRow]>rowUpper[iRow]+primalTolerance||
1503                        primalRowSolution[iRow]<rowLower[iRow]-primalTolerance) {
1504                      fprintf(fp,"** ");
1505                      type=2;
1506                    } else if (fabs(primalRowSolution[iRow])>1.0e-8) {
1507                      type=1;
1508                    } else if (numberRows<50) {
1509                      type=3;
1510                    } 
1511                    if (doMask&&!maskMatches(printMask,rowNames[iRow]))
1512                      type=0;
1513                    if (type) {
1514                      fprintf(fp,"%7d ",iRow);
1515                      if (lengthName)
1516                        fprintf(fp,format,rowNames[iRow].c_str());
1517                      fprintf(fp,"%15.8g        %15.8g\n",primalRowSolution[iRow],
1518                              dualRowSolution[iRow]);
1519                    }
1520                  }
1521                }
1522                int iColumn;
1523                int numberColumns=models[iModel].numberColumns();
1524                double * dualColumnSolution = 
1525                  models[iModel].dualColumnSolution();
1526                double * primalColumnSolution = 
1527                  models[iModel].primalColumnSolution();
1528                double * columnLower = models[iModel].columnLower();
1529                double * columnUpper = models[iModel].columnUpper();
1530                for (iColumn=0;iColumn<numberColumns;iColumn++) {
1531                  int type=(printMode>3) ? 1 : 0;
1532                  if (primalColumnSolution[iColumn]>columnUpper[iColumn]+primalTolerance||
1533                      primalColumnSolution[iColumn]<columnLower[iColumn]-primalTolerance) {
1534                    fprintf(fp,"** ");
1535                    type=2;
1536                  } else if (fabs(primalColumnSolution[iColumn])>1.0e-8) {
1537                    type=1;
1538                  } else if (numberColumns<50) {
1539                    type=3;
1540                  }
1541                  if (doMask&&!maskMatches(printMask,columnNames[iColumn]))
1542                    type =0;
1543                  if (type) {
1544                    fprintf(fp,"%7d ",iColumn);
1545                    if (lengthName)
1546                      fprintf(fp,format,columnNames[iColumn].c_str());
1547                    fprintf(fp,"%15.8g        %15.8g\n",
1548                            primalColumnSolution[iColumn],
1549                            dualColumnSolution[iColumn]);
1550                  }
1551                }
1552                if (fp!=stdout)
1553                  fclose(fp);
1554              } else {
1555                std::cout<<"Unable to open file "<<fileName<<std::endl;
1556              }
1557            } else {
1558              std::cout<<"** Current model not valid"<<std::endl;
1559             
1560            }
1561            break;
1562          case SAVESOL:
1563            if (goodModels[iModel]) {
1564              // get next field
1565              field = CoinReadGetString(argc,argv);
1566              if (field=="$") {
1567                field = parameters[iParam].stringValue();
1568              } else if (field=="EOL") {
1569                parameters[iParam].printString();
1570                break;
1571              } else {
1572                parameters[iParam].setStringValue(field);
1573              }
1574              std::string fileName;
1575              if (field[0]=='/'||field[0]=='\\') {
1576                fileName = field;
1577              } else if (field[0]=='~') {
1578                char * environVar = getenv("HOME");
1579                if (environVar) {
1580                  std::string home(environVar);
1581                  field=field.erase(0,1);
1582                  fileName = home+field;
1583                } else {
1584                  fileName=field;
1585                }
1586              } else {
1587                fileName = directory+field;
1588              }
1589              saveSolution(models+iModel,fileName);
1590            } else {
1591              std::cout<<"** Current model not valid"<<std::endl;
1592             
1593            }
1594            break;
1595          default:
1596            abort();
1597          }
1598        } 
1599      } else if (!numberMatches) {
1600        std::cout<<"No match for "<<field<<" - ? for list of commands"
1601                 <<std::endl;
1602      } else if (numberMatches==1) {
1603        if (!numberQuery) {
1604          std::cout<<"Short match for "<<field<<" - completion: ";
1605          std::cout<<parameters[firstMatch].matchName()<<std::endl;
1606        } else if (numberQuery) {
1607          std::cout<<parameters[firstMatch].matchName()<<" : ";
1608          std::cout<<parameters[firstMatch].shortHelp()<<std::endl;
1609          if (numberQuery>=2) 
1610            parameters[firstMatch].printLongHelp();
1611        }
1612      } else {
1613        if (!numberQuery) 
1614          std::cout<<"Multiple matches for "<<field<<" - possible completions:"
1615                   <<std::endl;
1616        else
1617          std::cout<<"Completions of "<<field<<":"<<std::endl;
1618        for ( iParam=0; iParam<numberParameters; iParam++ ) {
1619          int match = parameters[iParam].matches(field);
1620          if (match&&parameters[iParam].displayThis()) {
1621            std::cout<<parameters[iParam].matchName();
1622            if (numberQuery>=2) 
1623              std::cout<<" : "<<parameters[iParam].shortHelp();
1624            std::cout<<std::endl;
1625          }
1626        }
1627      }
1628    }
1629    delete [] models;
1630    delete [] goodModels;
1631  }
1632  // By now all memory should be freed
1633#ifdef DMALLOC
1634  dmalloc_log_unfreed();
1635  dmalloc_shutdown();
1636#endif
1637  return 0;
1638}   
1639static void breakdown(const char * name, int numberLook, const double * region)
1640{
1641  double range[] = {
1642    -COIN_DBL_MAX,
1643    -1.0e15,-1.0e11,-1.0e8,-1.0e5,-1.0e4,-1.0e3,-1.0e2,-1.0e1,
1644    -1.0,
1645    -1.0e-1,-1.0e-2,-1.0e-3,-1.0e-4,-1.0e-5,-1.0e-8,-1.0e-11,-1.0e-15,
1646    0.0,
1647    1.0e-15,1.0e-11,1.0e-8,1.0e-5,1.0e-4,1.0e-3,1.0e-2,1.0e-1,
1648    1.0,
1649    1.0e1,1.0e2,1.0e3,1.0e4,1.0e5,1.0e8,1.0e11,1.0e15,
1650    COIN_DBL_MAX};
1651  int nRanges = (int) (sizeof(range)/sizeof(double));
1652  int * number = new int[nRanges];
1653  memset(number,0,nRanges*sizeof(int));
1654  int * numberExact = new int[nRanges];
1655  memset(numberExact,0,nRanges*sizeof(int));
1656  int i;
1657  for ( i=0;i<numberLook;i++) {
1658    double value = region[i];
1659    for (int j=0;j<nRanges;j++) {
1660      if (value==range[j]) {
1661        numberExact[j]++;
1662        break;
1663      } else if (value<range[j]) {
1664        number[j]++;
1665        break;
1666      }
1667    }
1668  }
1669  printf("\n%s has %d entries\n",name,numberLook);
1670  for (i=0;i<nRanges;i++) {
1671    if (number[i]) 
1672      printf("%d between %g and %g",number[i],range[i-1],range[i]);
1673    if (numberExact[i]) {
1674      if (number[i])
1675        printf(", ");
1676      printf("%d exactly at %g",numberExact[i],range[i]);
1677    }
1678    if (number[i]+numberExact[i])
1679      printf("\n");
1680  }
1681  delete [] number;
1682  delete [] numberExact;
1683}
1684static void statistics(ClpSimplex * originalModel, ClpSimplex * model)
1685{
1686  int numberColumns = originalModel->numberColumns();
1687  const char * integerInformation  = originalModel->integerInformation(); 
1688  const double * columnLower = originalModel->columnLower();
1689  const double * columnUpper = originalModel->columnUpper();
1690  int numberIntegers=0;
1691  int numberBinary=0;
1692  int iRow,iColumn;
1693  if (integerInformation) {
1694    for (iColumn=0;iColumn<numberColumns;iColumn++) {
1695      if (integerInformation[iColumn]) {
1696        if (columnUpper[iColumn]>columnLower[iColumn]) {
1697          numberIntegers++;
1698          if (columnUpper[iColumn]==0.0&&columnLower[iColumn]==1) 
1699            numberBinary++;
1700        }
1701      }
1702    }
1703  }
1704  numberColumns = model->numberColumns();
1705  int numberRows = model->numberRows();
1706  columnLower = model->columnLower();
1707  columnUpper = model->columnUpper();
1708  const double * rowLower = model->rowLower();
1709  const double * rowUpper = model->rowUpper();
1710  const double * objective = model->objective();
1711  CoinPackedMatrix * matrix = model->matrix();
1712  CoinBigIndex numberElements = matrix->getNumElements();
1713  const int * columnLength = matrix->getVectorLengths();
1714  //const CoinBigIndex * columnStart = matrix->getVectorStarts();
1715  const double * elementByColumn = matrix->getElements();
1716  int * number = new int[numberRows+1];
1717  memset(number,0,(numberRows+1)*sizeof(int));
1718  int numberObjSingletons=0;
1719  /* cType
1720     0 0/inf, 1 0/up, 2 lo/inf, 3 lo/up, 4 free, 5 fix, 6 -inf/0, 7 -inf/up,
1721     8 0/1
1722  */ 
1723  int cType[9];
1724  std::string cName[]={"0.0->inf,","0.0->up,","lo->inf,","lo->up,","free,","fixed,","-inf->0.0,",
1725                       "-inf->up,","0.0->1.0"};
1726  int nObjective=0;
1727  memset(cType,0,sizeof(cType));
1728  for (iColumn=0;iColumn<numberColumns;iColumn++) {
1729    int length=columnLength[iColumn];
1730    if (length==1&&objective[iColumn])
1731      numberObjSingletons++;
1732    number[length]++;
1733    if (objective[iColumn])
1734      nObjective++;
1735    if (columnLower[iColumn]>-1.0e20) {
1736      if (columnLower[iColumn]==0.0) {
1737        if (columnUpper[iColumn]>1.0e20)
1738          cType[0]++;
1739        else if (columnUpper[iColumn]==1.0)
1740          cType[8]++;
1741        else if (columnUpper[iColumn]==0.0)
1742          cType[5]++;
1743        else
1744          cType[1]++;
1745      } else {
1746        if (columnUpper[iColumn]>1.0e20) 
1747          cType[2]++;
1748        else if (columnUpper[iColumn]==columnLower[iColumn])
1749          cType[5]++;
1750        else
1751          cType[3]++;
1752      }
1753    } else {
1754      if (columnUpper[iColumn]>1.0e20) 
1755        cType[4]++;
1756      else if (columnUpper[iColumn]==0.0) 
1757        cType[6]++;
1758      else
1759        cType[7]++;
1760    }
1761  }
1762  /* rType
1763     0 E 0, 1 E 1, 2 E -1, 3 E other, 4 G 0, 5 G 1, 6 G other,
1764     7 L 0,  8 L 1, 9 L other, 10 Range 0/1, 11 Range other, 12 free
1765  */ 
1766  int rType[13];
1767  std::string rName[]={"E 0.0,","E 1.0,","E -1.0,","E other,","G 0.0,","G 1.0,","G other,",
1768                       "L 0.0,","L 1.0,","L other,","Range 0.0->1.0,","Range other,","Free"};
1769  memset(rType,0,sizeof(rType));
1770  for (iRow=0;iRow<numberRows;iRow++) {
1771    if (rowLower[iRow]>-1.0e20) {
1772      if (rowLower[iRow]==0.0) {
1773        if (rowUpper[iRow]>1.0e20)
1774          rType[4]++;
1775        else if (rowUpper[iRow]==1.0)
1776          rType[10]++;
1777        else if (rowUpper[iRow]==0.0)
1778          rType[0]++;
1779        else
1780          rType[11]++;
1781      } else if (rowLower[iRow]==1.0) {
1782        if (rowUpper[iRow]>1.0e20) 
1783          rType[5]++;
1784        else if (rowUpper[iRow]==rowLower[iRow])
1785          rType[1]++;
1786        else
1787          rType[11]++;
1788      } else if (rowLower[iRow]==-1.0) {
1789        if (rowUpper[iRow]>1.0e20) 
1790          rType[6]++;
1791        else if (rowUpper[iRow]==rowLower[iRow])
1792          rType[2]++;
1793        else
1794          rType[11]++;
1795      } else {
1796        if (rowUpper[iRow]>1.0e20) 
1797          rType[6]++;
1798        else if (rowUpper[iRow]==rowLower[iRow])
1799          rType[3]++;
1800        else
1801          rType[11]++;
1802      }
1803    } else {
1804      if (rowUpper[iRow]>1.0e20) 
1805        rType[12]++;
1806      else if (rowUpper[iRow]==0.0) 
1807        rType[7]++;
1808      else if (rowUpper[iRow]==1.0) 
1809        rType[8]++;
1810      else
1811        rType[9]++;
1812    }
1813  }
1814  // Basic statistics
1815  printf("\n\nProblem has %d rows, %d columns (%d with objective) and %d elements\n",
1816         numberRows,numberColumns,nObjective,numberElements);
1817  if (number[0]+number[1]) {
1818    printf("There are ");
1819    if (numberObjSingletons)
1820      printf("%d singletons with objective ",numberObjSingletons);
1821    int numberNoObj = number[1]-numberObjSingletons;
1822    if (numberNoObj)
1823      printf("%d singletons with no objective ",numberNoObj);
1824    if (number[0])
1825      printf("** %d columns have no entries",number[0]);
1826    printf("\n");
1827  }
1828  printf("Column breakdown:\n");
1829  int k;
1830  for (k=0;k<(int) (sizeof(cType)/sizeof(int));k++) {
1831    printf("%d of type %s ",cType[k],cName[k].c_str());
1832    if (((k+1)%3)==0)
1833      printf("\n");
1834  }
1835  if ((k%3)!=0)
1836    printf("\n");
1837  printf("Row breakdown:\n");
1838  for (k=0;k<(int) (sizeof(rType)/sizeof(int));k++) {
1839    printf("%d of type %s ",rType[k],rName[k].c_str());
1840    if (((k+1)%3)==0)
1841      printf("\n");
1842  }
1843  if ((k%3)!=0)
1844    printf("\n");
1845  if (model->logLevel()<2)
1846    return ;
1847  int kMax = model->logLevel()>3 ? 1000000 : 10;
1848  k=0;
1849  for (iRow=1;iRow<=numberRows;iRow++) {
1850    if (number[iRow]) {
1851      k++;
1852      printf("%d columns have %d entries\n",number[iRow],iRow);
1853      if (k==kMax)
1854        break;
1855    }
1856  }
1857  if (k<numberRows) {
1858    int kk=k;
1859    k=0;
1860    for (iRow=numberRows;iRow>=1;iRow--) {
1861      if (number[iRow]) {
1862        k++;
1863        if (k==kMax)
1864          break;
1865      }
1866    }
1867    if (k>kk) {
1868      printf("\n    .........\n\n");
1869      iRow=k;
1870      k=0;
1871      for (;iRow<numberRows;iRow++) {
1872        if (number[iRow]) {
1873          k++;
1874          printf("%d columns have %d entries\n",number[iRow],iRow);
1875          if (k==kMax)
1876            break;
1877        }
1878      }
1879    }
1880  }
1881  delete [] number;
1882  printf("\n\n");
1883  // get row copy
1884  CoinPackedMatrix rowCopy = *matrix;
1885  rowCopy.reverseOrdering();
1886  //const int * column = rowCopy.getIndices();
1887  const int * rowLength = rowCopy.getVectorLengths();
1888  //const CoinBigIndex * rowStart = rowCopy.getVectorStarts();
1889  //const double * element = rowCopy.getElements();
1890  number = new int[numberColumns+1];
1891  memset(number,0,(numberColumns+1)*sizeof(int));
1892  for (iRow=0;iRow<numberRows;iRow++) {
1893    int length=rowLength[iRow];
1894    number[length]++;
1895  }
1896  if (number[0])
1897    printf("** %d rows have no entries\n",number[0]);
1898  k=0;
1899  for (iColumn=1;iColumn<=numberColumns;iColumn++) {
1900    if (number[iColumn]) {
1901      k++;
1902      printf("%d rows have %d entries\n",number[iColumn],iColumn);
1903      if (k==kMax)
1904        break;
1905    }
1906  }
1907  if (k<numberColumns) {
1908    int kk=k;
1909    k=0;
1910    for (iColumn=numberColumns;iColumn>=1;iColumn--) {
1911      if (number[iColumn]) {
1912        k++;
1913        if (k==kMax)
1914          break;
1915      }
1916    }
1917    if (k>kk) {
1918      printf("\n    .........\n\n");
1919      iColumn=k;
1920      k=0;
1921      for (;iColumn<numberColumns;iColumn++) {
1922        if (number[iColumn]) {
1923          k++;
1924          printf("%d rows have %d entries\n",number[iColumn],iColumn);
1925          if (k==kMax)
1926            break;
1927        }
1928      }
1929    }
1930  }
1931  delete [] number;
1932  // Now do breakdown of ranges
1933  breakdown("Elements",numberElements,elementByColumn);
1934  breakdown("RowLower",numberRows,rowLower);
1935  breakdown("RowUpper",numberRows,rowUpper);
1936  breakdown("ColumnLower",numberColumns,columnLower);
1937  breakdown("ColumnUpper",numberColumns,columnUpper);
1938  breakdown("Objective",numberColumns,objective);
1939}
1940static bool maskMatches(std::string & mask, std::string & check)
1941{
1942  // back to char as I am old fashioned
1943  const char * maskC = mask.c_str();
1944  const char * checkC = check.c_str();
1945  int length = strlen(maskC);
1946  int lengthCheck;
1947  for (lengthCheck=length-1;lengthCheck>=0;lengthCheck--) {
1948    if (maskC[lengthCheck]!='*')
1949      break;
1950  }
1951  lengthCheck++;
1952  int lengthC = strlen(checkC);
1953  if (lengthC>length)
1954    return false; // can't be true
1955  if (lengthC<lengthCheck) {
1956    // last lot must be blank for match
1957    for (int i=lengthC;i<lengthCheck;i++) {
1958      if (maskC[i]!=' ')
1959        return false;
1960    }
1961  }
1962  // need only check this much
1963  lengthC = CoinMin(lengthC,lengthCheck);
1964  for (int i=0;i<lengthC;i++) {
1965    if (maskC[i]!='*'&&maskC[i]!=checkC[i])
1966      return false;
1967  }
1968  return true; // matches
1969}
1970/*
1971  Version 1.00.00 October 13 2004.
1972  1.00.01 October 18.  Added basis handline helped/prodded by Thorsten Koch.
1973  Also modifications to make faster with sbb (I hope I haven't broken anything).
1974  1.00.02 March 21 2005.  Redid ClpNonLinearCost to save memory also redid
1975  createRim to try and improve cache characteristics.
1976  1.00.03 April 8 2005.  Added Volume algorithm as crash and made code more
1977  robust on testing.  Also added "either" and "tune" algorithm.
1978  1.01.01 April 12 2005.  Decided to go to different numbering.  Backups will
1979  be last 2 digits while middle 2 are for improvements.  Still take a long
1980  time to get to 2.00.01
1981  1.01.02 May 4 2005.  Will be putting in many changes - so saving stable version
1982  1.02.01 May 6 2005.  Lots of changes to try and make faster and more stable in
1983  branch and cut.
1984  1.02.02 May 19 2005.  Stuff for strong branching and some improvements to simplex
1985 */
Note: See TracBrowser for help on using the repository browser.