source: trunk/Test/unitTest.cpp @ 118

Last change on this file since 118 was 118, checked in by forrest, 17 years ago

Adding Network matrix and PlusMinusOne?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.8 KB
Line 
1// Copyright (C) 2002, International Business Machines
2// Corporation and others.  All Rights Reserved.
3
4#include "CoinPragma.hpp"
5#include <cassert>
6#include <cstdio>
7#include <cmath>
8#include <cfloat>
9#include <string>
10#include <iostream>
11
12#include <time.h>
13
14#include "CoinMpsIO.hpp"
15#include "CoinPackedMatrix.hpp"
16#include "CoinPackedVector.hpp"
17#include "CoinHelperFunctions.hpp"
18
19#include "ClpFactorization.hpp"
20#include "ClpSimplex.hpp"
21#include "ClpDualRowSteepest.hpp"
22#include "ClpDualRowDantzig.hpp"
23#include "ClpPrimalColumnSteepest.hpp"
24#include "ClpPrimalColumnDantzig.hpp"
25#include "ClpParameters.hpp"
26#include "ClpNetworkMatrix.hpp"
27#include "ClpPlusMinusOneMatrix.hpp"
28
29#include "Presolve.hpp"
30#ifdef CLP_IDIOT
31#include "Idiot.hpp"
32#endif
33
34
35#include <time.h>
36#ifndef _MSC_VER
37#include <sys/times.h>
38#include <sys/resource.h>
39#include <unistd.h>
40#endif
41
42static double cpuTime()
43{
44  double cpu_temp;
45#if defined(_MSC_VER)
46  unsigned int ticksnow;        /* clock_t is same as int */
47 
48  ticksnow = (unsigned int)clock();
49 
50  cpu_temp = (double)((double)ticksnow/CLOCKS_PER_SEC);
51#else
52  struct rusage usage;
53  getrusage(RUSAGE_SELF,&usage);
54  cpu_temp = usage.ru_utime.tv_sec;
55  cpu_temp += 1.0e-6*((double) usage.ru_utime.tv_usec);
56#endif
57  return cpu_temp;
58}
59
60
61//#############################################################################
62
63#ifdef NDEBUG
64#undef NDEBUG
65#endif
66
67// Function Prototypes. Function definitions is in this file.
68void testingMessage( const char * const msg );
69
70//----------------------------------------------------------------
71// unitTest [-mpsDir=V1] [-netlibDir=V2] [-netlib]
72//
73// where:
74//   -mpsDir: directory containing mps test files
75//       Default value V1="../Mps/Sample"   
76//   -netlibDir: directory containing netlib files
77//       Default value V2="../Mps/Netlib"
78//   -netlib
79//       If specified, then netlib test set run
80//
81// All parameters are optional.
82//----------------------------------------------------------------
83int mainTest (int argc, const char *argv[],bool doDual,
84              ClpSimplex empty, bool doPresolve,int doIdiot)
85{
86  int i;
87
88  // define valid parameter keywords
89  std::set<std::string> definedKeyWords;
90  definedKeyWords.insert("-mpsDir");
91  definedKeyWords.insert("-netlibDir");
92  definedKeyWords.insert("-netlib");
93
94  // Create a map of parameter keys and associated data
95  std::map<std::string,std::string> parms;
96  for ( i=1; i<argc; i++ ) {
97    std::string parm(argv[i]);
98    std::string key,value;
99    unsigned int  eqPos = parm.find('=');
100
101    // Does parm contain and '='
102    if ( eqPos==std::string::npos ) {
103      //Parm does not contain '='
104      key = parm;
105    }
106    else {
107      key=parm.substr(0,eqPos);
108      value=parm.substr(eqPos+1);
109    }
110
111    // Is specifed key valid?
112    if ( definedKeyWords.find(key) == definedKeyWords.end() ) {
113      // invalid key word.
114      // Write help text
115      std::cerr <<"Undefined parameter \"" <<key <<"\".\n";
116      std::cerr <<"Correct usage: \n";
117      std::cerr <<"  unitTest [-mpsDir=V1] [-netlibDir=V2] [-netlib]\n";
118      std::cerr <<"  where:\n";
119      std::cerr <<"    -mpsDir: directory containing mps test files\n";
120      std::cerr <<"        Default value V1=\"../Mps/Sample\"\n";
121      std::cerr <<"    -netlibDir: directory containing netlib files\n";
122      std::cerr <<"        Default value V2=\"../Mps/Netlib\"\n";
123      std::cerr <<"    -netlib\n";
124      std::cerr <<"        If specified, then netlib testset run.\n";
125      return 1;
126    }
127    parms[key]=value;
128  }
129 
130  const char dirsep =  CoinFindDirSeparator();
131  // Set directory containing mps data files.
132  std::string mpsDir;
133  if (parms.find("-mpsDir") != parms.end())
134    mpsDir=parms["-mpsDir"] + dirsep;
135  else 
136    mpsDir = dirsep == '/' ? "../Mps/Sample/" : "..\\Mps\\Sample\\";
137 
138  // Set directory containing netlib data files.
139  std::string netlibDir;
140  if (parms.find("-netlibDir") != parms.end())
141    netlibDir=parms["-netlibDir"] + dirsep;
142  else 
143    netlibDir = dirsep == '/' ? "../Mps/Netlib/" : "..\\Mps\\Netlib\\";
144
145  testingMessage( "Testing ClpSimplex\n" );
146  ClpSimplexUnitTest(mpsDir,netlibDir);
147  if (parms.find("-netlib") != parms.end())
148  {
149    unsigned int m;
150   
151    // Define test problems:
152    //   mps names,
153    //   maximization or minimization,
154    //   Number of rows and columns in problem, and
155    //   objective function value
156    std::vector<std::string> mpsName;
157    std::vector<bool> min;
158    std::vector<int> nRows;
159    std::vector<int> nCols;
160    std::vector<double> objValue;
161    std::vector<double> objValueTol;
162    mpsName.push_back("25fv47");
163    min.push_back(true);
164    nRows.push_back(822);
165    nCols.push_back(1571);
166    objValueTol.push_back(1.E-10);
167    objValue.push_back(5.5018458883E+03);
168
169    mpsName.push_back("80bau3b");min.push_back(true);nRows.push_back(2263);nCols.push_back(9799);objValueTol.push_back(1.e-10);objValue.push_back(9.8722419241E+05);
170    mpsName.push_back("blend");min.push_back(true);nRows.push_back(75);nCols.push_back(83);objValueTol.push_back(1.e-10);objValue.push_back(-3.0812149846e+01);
171    mpsName.push_back("pilotnov");min.push_back(true);nRows.push_back(976);nCols.push_back(2172);objValueTol.push_back(1.e-10);objValue.push_back(-4.4972761882e+03);
172    mpsName.push_back("maros-r7");min.push_back(true);nRows.push_back(3137);nCols.push_back(9408);objValueTol.push_back(1.e-10);objValue.push_back(1.4971851665e+06);
173   
174    mpsName.push_back("pilot");min.push_back(true);nRows.push_back(1442);nCols.push_back(3652);objValueTol.push_back(1.e-5);objValue.push_back(/*-5.5740430007e+02*/-557.48972927292);
175    mpsName.push_back("pilot4");min.push_back(true);nRows.push_back(411);nCols.push_back(1000);objValueTol.push_back(1.e-8);objValue.push_back(-2.5811392641e+03);
176    mpsName.push_back("pilot87");min.push_back(true);nRows.push_back(2031);nCols.push_back(4883);objValueTol.push_back(1.e-4);objValue.push_back(3.0171072827e+02);
177    mpsName.push_back("adlittle");min.push_back(true);nRows.push_back(57);nCols.push_back(97);objValueTol.push_back(1.e-10);objValue.push_back(2.2549496316e+05);
178    mpsName.push_back("afiro");min.push_back(true);nRows.push_back(28);nCols.push_back(32);objValueTol.push_back(1.e-10);objValue.push_back(-4.6475314286e+02);
179    mpsName.push_back("agg");min.push_back(true);nRows.push_back(489);nCols.push_back(163);objValueTol.push_back(1.e-10);objValue.push_back(-3.5991767287e+07);
180    mpsName.push_back("agg2");min.push_back(true);nRows.push_back(517);nCols.push_back(302);objValueTol.push_back(1.e-10);objValue.push_back(-2.0239252356e+07);
181    mpsName.push_back("agg3");min.push_back(true);nRows.push_back(517);nCols.push_back(302);objValueTol.push_back(1.e-10);objValue.push_back(1.0312115935e+07);
182    mpsName.push_back("bandm");min.push_back(true);nRows.push_back(306);nCols.push_back(472);objValueTol.push_back(1.e-10);objValue.push_back(-1.5862801845e+02);
183    mpsName.push_back("beaconfd");min.push_back(true);nRows.push_back(174);nCols.push_back(262);objValueTol.push_back(1.e-10);objValue.push_back(3.3592485807e+04);
184    mpsName.push_back("bnl1");min.push_back(true);nRows.push_back(644);nCols.push_back(1175);objValueTol.push_back(1.e-10);objValue.push_back(1.9776295615E+03);
185    mpsName.push_back("bnl2");min.push_back(true);nRows.push_back(2325);nCols.push_back(3489);objValueTol.push_back(1.e-10);objValue.push_back(1.8112365404e+03);
186    mpsName.push_back("boeing1");min.push_back(true);nRows.push_back(/*351*/352);nCols.push_back(384);objValueTol.push_back(1.e-10);objValue.push_back(-3.3521356751e+02);
187    mpsName.push_back("boeing2");min.push_back(true);nRows.push_back(167);nCols.push_back(143);objValueTol.push_back(1.e-10);objValue.push_back(-3.1501872802e+02);
188    mpsName.push_back("bore3d");min.push_back(true);nRows.push_back(234);nCols.push_back(315);objValueTol.push_back(1.e-10);objValue.push_back(1.3730803942e+03);
189    mpsName.push_back("brandy");min.push_back(true);nRows.push_back(221);nCols.push_back(249);objValueTol.push_back(1.e-10);objValue.push_back(1.5185098965e+03);
190    mpsName.push_back("capri");min.push_back(true);nRows.push_back(272);nCols.push_back(353);objValueTol.push_back(1.e-10);objValue.push_back(2.6900129138e+03);
191    mpsName.push_back("cycle");min.push_back(true);nRows.push_back(1904);nCols.push_back(2857);objValueTol.push_back(1.e-9);objValue.push_back(-5.2263930249e+00);
192    mpsName.push_back("czprob");min.push_back(true);nRows.push_back(930);nCols.push_back(3523);objValueTol.push_back(1.e-10);objValue.push_back(2.1851966989e+06);
193    mpsName.push_back("d2q06c");min.push_back(true);nRows.push_back(2172);nCols.push_back(5167);objValueTol.push_back(1.e-7);objValue.push_back(122784.21557456);
194    mpsName.push_back("d6cube");min.push_back(true);nRows.push_back(416);nCols.push_back(6184);objValueTol.push_back(1.e-7);objValue.push_back(3.1549166667e+02);
195    mpsName.push_back("degen2");min.push_back(true);nRows.push_back(445);nCols.push_back(534);objValueTol.push_back(1.e-10);objValue.push_back(-1.4351780000e+03);
196    mpsName.push_back("degen3");min.push_back(true);nRows.push_back(1504);nCols.push_back(1818);objValueTol.push_back(1.e-10);objValue.push_back(-9.8729400000e+02);
197    mpsName.push_back("dfl001");min.push_back(true);nRows.push_back(6072);nCols.push_back(12230);objValueTol.push_back(1.e-5);objValue.push_back(1.1266396047E+07);
198    mpsName.push_back("e226");min.push_back(true);nRows.push_back(224);nCols.push_back(282);objValueTol.push_back(1.e-10);objValue.push_back(-1.8751929066e+01+7.113); // The correct answer includes -7.113 term. This is a constant in the objective function. See line 1683 of the mps file.
199    mpsName.push_back("etamacro");min.push_back(true);nRows.push_back(401);nCols.push_back(688);objValueTol.push_back(1.e-6);objValue.push_back(-7.5571521774e+02 );
200    mpsName.push_back("fffff800");min.push_back(true);nRows.push_back(525);nCols.push_back(854);objValueTol.push_back(1.e-6);objValue.push_back(5.5567961165e+05);
201    mpsName.push_back("finnis");min.push_back(true);nRows.push_back(498);nCols.push_back(614);objValueTol.push_back(1.e-6);objValue.push_back(1.7279096547e+05);
202    mpsName.push_back("fit1d");min.push_back(true);nRows.push_back(25);nCols.push_back(1026);objValueTol.push_back(1.e-10);objValue.push_back(-9.1463780924e+03);
203    mpsName.push_back("fit1p");min.push_back(true);nRows.push_back(628);nCols.push_back(1677);objValueTol.push_back(1.e-10);objValue.push_back(9.1463780924e+03);
204    mpsName.push_back("fit2d");min.push_back(true);nRows.push_back(26);nCols.push_back(10500);objValueTol.push_back(1.e-10);objValue.push_back(-6.8464293294e+04);
205    mpsName.push_back("fit2p");min.push_back(true);nRows.push_back(3001);nCols.push_back(13525);objValueTol.push_back(1.e-9);objValue.push_back(6.8464293232e+04);
206    mpsName.push_back("forplan");min.push_back(true);nRows.push_back(162);nCols.push_back(421);objValueTol.push_back(1.e-6);objValue.push_back(-6.6421873953e+02);
207    mpsName.push_back("ganges");min.push_back(true);nRows.push_back(1310);nCols.push_back(1681);objValueTol.push_back(1.e-5);objValue.push_back(-1.0958636356e+05);
208    mpsName.push_back("gfrd-pnc");min.push_back(true);nRows.push_back(617);nCols.push_back(1092);objValueTol.push_back(1.e-10);objValue.push_back(6.9022359995e+06);
209    mpsName.push_back("greenbea");min.push_back(true);nRows.push_back(2393);nCols.push_back(5405);objValueTol.push_back(1.e-10);objValue.push_back(/*-7.2462405908e+07*/-72555248.129846);
210    mpsName.push_back("greenbeb");min.push_back(true);nRows.push_back(2393);nCols.push_back(5405);objValueTol.push_back(1.e-10);objValue.push_back(/*-4.3021476065e+06*/-4302260.2612066);
211    mpsName.push_back("grow15");min.push_back(true);nRows.push_back(301);nCols.push_back(645);objValueTol.push_back(1.e-10);objValue.push_back(-1.0687094129e+08);
212    mpsName.push_back("grow22");min.push_back(true);nRows.push_back(441);nCols.push_back(946);objValueTol.push_back(1.e-10);objValue.push_back(-1.6083433648e+08);
213    mpsName.push_back("grow7");min.push_back(true);nRows.push_back(141);nCols.push_back(301);objValueTol.push_back(1.e-10);objValue.push_back(-4.7787811815e+07);
214    mpsName.push_back("israel");min.push_back(true);nRows.push_back(175);nCols.push_back(142);objValueTol.push_back(1.e-10);objValue.push_back(-8.9664482186e+05);
215    mpsName.push_back("kb2");min.push_back(true);nRows.push_back(44);nCols.push_back(41);objValueTol.push_back(1.e-10);objValue.push_back(-1.7499001299e+03);
216    mpsName.push_back("lotfi");min.push_back(true);nRows.push_back(154);nCols.push_back(308);objValueTol.push_back(1.e-10);objValue.push_back(-2.5264706062e+01);
217    mpsName.push_back("maros");min.push_back(true);nRows.push_back(847);nCols.push_back(1443);objValueTol.push_back(1.e-10);objValue.push_back(-5.8063743701e+04);
218    mpsName.push_back("modszk1");min.push_back(true);nRows.push_back(688);nCols.push_back(1620);objValueTol.push_back(1.e-10);objValue.push_back(3.2061972906e+02);
219    mpsName.push_back("nesm");min.push_back(true);nRows.push_back(663);nCols.push_back(2923);objValueTol.push_back(1.e-5);objValue.push_back(1.4076073035e+07);
220    mpsName.push_back("perold");min.push_back(true);nRows.push_back(626);nCols.push_back(1376);objValueTol.push_back(1.e-6);objValue.push_back(-9.3807580773e+03);
221    //mpsName.push_back("qap12");min.push_back(true);nRows.push_back(3193);nCols.push_back(8856);objValueTol.push_back(1.e-6);objValue.push_back(5.2289435056e+02);
222    //mpsName.push_back("qap15");min.push_back(true);nRows.push_back(6331);nCols.push_back(22275);objValueTol.push_back(1.e-10);objValue.push_back(1.0409940410e+03);
223    mpsName.push_back("recipe");min.push_back(true);nRows.push_back(92);nCols.push_back(180);objValueTol.push_back(1.e-10);objValue.push_back(-2.6661600000e+02);
224    mpsName.push_back("sc105");min.push_back(true);nRows.push_back(106);nCols.push_back(103);objValueTol.push_back(1.e-10);objValue.push_back(-5.2202061212e+01);
225    mpsName.push_back("sc205");min.push_back(true);nRows.push_back(206);nCols.push_back(203);objValueTol.push_back(1.e-10);objValue.push_back(-5.2202061212e+01);
226    mpsName.push_back("sc50a");min.push_back(true);nRows.push_back(51);nCols.push_back(48);objValueTol.push_back(1.e-10);objValue.push_back(-6.4575077059e+01);
227    mpsName.push_back("sc50b");min.push_back(true);nRows.push_back(51);nCols.push_back(48);objValueTol.push_back(1.e-10);objValue.push_back(-7.0000000000e+01);
228    mpsName.push_back("scagr25");min.push_back(true);nRows.push_back(472);nCols.push_back(500);objValueTol.push_back(1.e-10);objValue.push_back(-1.4753433061e+07);
229    mpsName.push_back("scagr7");min.push_back(true);nRows.push_back(130);nCols.push_back(140);objValueTol.push_back(1.e-6);objValue.push_back(-2.3313892548e+06);
230    mpsName.push_back("scfxm1");min.push_back(true);nRows.push_back(331);nCols.push_back(457);objValueTol.push_back(1.e-10);objValue.push_back(1.8416759028e+04);
231    mpsName.push_back("scfxm2");min.push_back(true);nRows.push_back(661);nCols.push_back(914);objValueTol.push_back(1.e-10);objValue.push_back(3.6660261565e+04);
232    mpsName.push_back("scfxm3");min.push_back(true);nRows.push_back(991);nCols.push_back(1371);objValueTol.push_back(1.e-10);objValue.push_back(5.4901254550e+04);
233    mpsName.push_back("scorpion");min.push_back(true);nRows.push_back(389);nCols.push_back(358);objValueTol.push_back(1.e-10);objValue.push_back(1.8781248227e+03);
234    mpsName.push_back("scrs8");min.push_back(true);nRows.push_back(491);nCols.push_back(1169);objValueTol.push_back(1.e-5);objValue.push_back(9.0429998619e+02);
235    mpsName.push_back("scsd1");min.push_back(true);nRows.push_back(78);nCols.push_back(760);objValueTol.push_back(1.e-10);objValue.push_back(8.6666666743e+00);
236    mpsName.push_back("scsd6");min.push_back(true);nRows.push_back(148);nCols.push_back(1350);objValueTol.push_back(1.e-10);objValue.push_back(5.0500000078e+01);
237    mpsName.push_back("scsd8");min.push_back(true);nRows.push_back(398);nCols.push_back(2750);objValueTol.push_back(1.e-10);objValue.push_back(9.0499999993e+02);
238    mpsName.push_back("sctap1");min.push_back(true);nRows.push_back(301);nCols.push_back(480);objValueTol.push_back(1.e-10);objValue.push_back(1.4122500000e+03);
239    mpsName.push_back("sctap2");min.push_back(true);nRows.push_back(1091);nCols.push_back(1880);objValueTol.push_back(1.e-10);objValue.push_back(1.7248071429e+03);
240    mpsName.push_back("sctap3");min.push_back(true);nRows.push_back(1481);nCols.push_back(2480);objValueTol.push_back(1.e-10);objValue.push_back(1.4240000000e+03);
241    mpsName.push_back("seba");min.push_back(true);nRows.push_back(516);nCols.push_back(1028);objValueTol.push_back(1.e-10);objValue.push_back(1.5711600000e+04);
242    mpsName.push_back("share1b");min.push_back(true);nRows.push_back(118);nCols.push_back(225);objValueTol.push_back(1.e-10);objValue.push_back(-7.6589318579e+04);
243    mpsName.push_back("share2b");min.push_back(true);nRows.push_back(97);nCols.push_back(79);objValueTol.push_back(1.e-10);objValue.push_back(-4.1573224074e+02);
244    mpsName.push_back("shell");min.push_back(true);nRows.push_back(537);nCols.push_back(1775);objValueTol.push_back(1.e-10);objValue.push_back(1.2088253460e+09);
245    mpsName.push_back("ship04l");min.push_back(true);nRows.push_back(403);nCols.push_back(2118);objValueTol.push_back(1.e-10);objValue.push_back(1.7933245380e+06);
246    mpsName.push_back("ship04s");min.push_back(true);nRows.push_back(403);nCols.push_back(1458);objValueTol.push_back(1.e-10);objValue.push_back(1.7987147004e+06);
247    mpsName.push_back("ship08l");min.push_back(true);nRows.push_back(779);nCols.push_back(4283);objValueTol.push_back(1.e-10);objValue.push_back(1.9090552114e+06);
248    mpsName.push_back("ship08s");min.push_back(true);nRows.push_back(779);nCols.push_back(2387);objValueTol.push_back(1.e-10);objValue.push_back(1.9200982105e+06);
249    mpsName.push_back("ship12l");min.push_back(true);nRows.push_back(1152);nCols.push_back(5427);objValueTol.push_back(1.e-10);objValue.push_back(1.4701879193e+06);
250    mpsName.push_back("ship12s");min.push_back(true);nRows.push_back(1152);nCols.push_back(2763);objValueTol.push_back(1.e-10);objValue.push_back(1.4892361344e+06);
251    mpsName.push_back("sierra");min.push_back(true);nRows.push_back(1228);nCols.push_back(2036);objValueTol.push_back(1.e-10);objValue.push_back(1.5394362184e+07);
252    mpsName.push_back("stair");min.push_back(true);nRows.push_back(357);nCols.push_back(467);objValueTol.push_back(1.e-10);objValue.push_back(-2.5126695119e+02);
253    mpsName.push_back("standata");min.push_back(true);nRows.push_back(360);nCols.push_back(1075);objValueTol.push_back(1.e-10);objValue.push_back(1.2576995000e+03);
254    //mpsName.push_back("standgub");min.push_back(true);nRows.push_back(362);nCols.push_back(1184);objValueTol.push_back(1.e-10);objValue.push_back(1257.6995);
255    mpsName.push_back("standmps");min.push_back(true);nRows.push_back(468);nCols.push_back(1075);objValueTol.push_back(1.e-10);objValue.push_back(1.4060175000E+03); 
256    mpsName.push_back("stocfor1");min.push_back(true);nRows.push_back(118);nCols.push_back(111);objValueTol.push_back(1.e-10);objValue.push_back(-4.1131976219E+04);
257    mpsName.push_back("stocfor2");min.push_back(true);nRows.push_back(2158);nCols.push_back(2031);objValueTol.push_back(1.e-10);objValue.push_back(-3.9024408538e+04);
258    //mpsName.push_back("stocfor3");min.push_back(true);nRows.push_back(16676);nCols.push_back(15695);objValueTol.push_back(1.e-10);objValue.push_back(-3.9976661576e+04);
259    //mpsName.push_back("truss");min.push_back(true);nRows.push_back(1001);nCols.push_back(8806);objValueTol.push_back(1.e-10);objValue.push_back(4.5881584719e+05);
260    mpsName.push_back("tuff");min.push_back(true);nRows.push_back(334);nCols.push_back(587);objValueTol.push_back(1.e-10);objValue.push_back(2.9214776509e-01);
261    mpsName.push_back("vtpbase");min.push_back(true);nRows.push_back(199);nCols.push_back(203);objValueTol.push_back(1.e-10);objValue.push_back(1.2983146246e+05);
262    mpsName.push_back("wood1p");min.push_back(true);nRows.push_back(245);nCols.push_back(2594);objValueTol.push_back(1.e-10);objValue.push_back(1.4429024116e+00);
263    mpsName.push_back("woodw");min.push_back(true);nRows.push_back(1099);nCols.push_back(8405);objValueTol.push_back(1.e-10);objValue.push_back(1.3044763331E+00);
264
265    double timeTaken =0.0;
266  // Loop once for each Mps File
267    for (m=0; m<mpsName.size(); m++ ) {
268      std::cerr <<"  processing mps file: " <<mpsName[m] 
269                <<" (" <<m+1 <<" out of " <<mpsName.size() <<")" <<std::endl;
270   
271      // Read data mps file,
272      std::string fn = netlibDir+mpsName[m];
273      CoinMpsIO mps;
274      mps.readMps(fn.c_str(),"mps");
275      double time1 = cpuTime();
276      ClpSimplex solution=empty;
277      solution.loadProblem(*mps.getMatrixByCol(),mps.getColLower(),
278                           mps.getColUpper(),
279                           mps.getObjCoefficients(),
280                           mps.getRowLower(),mps.getRowUpper());
281
282      solution.setDblParam(ClpObjOffset,mps.objectiveOffset());
283#if 0
284      solution.setOptimizationDirection(-1);
285      {
286        int j;
287        double * obj = solution.objective();
288        int n=solution.numberColumns();
289        for (j=0;j<n;j++)
290          obj[j] *= -1.0;
291      }
292#endif
293      if (doPresolve) {
294#ifdef USE_PRESOLVE
295        Presolve pinfo;
296        ClpSimplex * model2 = pinfo.presolvedModel(solution,1.0e-8);
297        // change from 200 (unless user has changed)
298        if (model2->factorization()->maximumPivots()==200)
299          model2->factorization()->maximumPivots(100+model2->numberRows()/100);
300        if (doDual) {
301          // faster if bounds tightened
302          int numberInfeasibilities = model2->tightenPrimalBounds();
303          if (numberInfeasibilities)
304            std::cout<<"** Analysis indicates model infeasible"
305                     <<std::endl;
306          if (doIdiot<0)
307            model2->crash(1000,2);
308          model2->dual();
309        } else {
310#ifdef CLP_IDIOT
311          if (doIdiot>0) {
312            Idiot info(*model2);
313            info.crash(doIdiot);
314          }
315#endif
316          model2->primal(1);
317        }
318        pinfo.postsolve(true);
319       
320        delete model2;
321#if 1
322        printf("Resolving from postsolved model\n");
323        // later try without (1) and check duals before solve
324        solution.primal(1);
325        if (solution.numberIterations())
326          printf("****** iterated %d\n",solution.numberIterations());
327        /*solution.checkSolution();
328        printf("%g dual %g(%d) Primal %g(%d)\n",
329               solution.objectiveValue(),
330               solution.sumDualInfeasibilities(),
331               solution.numberDualInfeasibilities(),
332               solution.sumPrimalInfeasibilities(),
333               solution.numberPrimalInfeasibilities());*/
334#endif
335        if (0) {
336          Presolve pinfoA;
337          model2 = pinfoA.presolvedModel(solution,1.0e-8);
338
339          printf("Resolving from presolved optimal solution\n");
340          model2->primal(1);
341               
342          delete model2;
343        }
344#else
345        if (doDual) {
346          if (doIdiot<0)
347            solution.crash(1000,2);
348          solution.dual();
349        } else {
350#ifdef CLP_IDIOT
351          if (doIdiot>0) {
352            Idiot info(solution);
353            info.crash(doIdiot);
354          }
355#endif
356          solution.primal(1);
357        }
358#endif
359      } else {
360        if (doDual) {
361          if (doIdiot<0)
362            solution.crash(1000,2);
363          solution.dual();
364        } else {
365#ifdef CLP_IDIOT
366          if (doIdiot>0) {
367            Idiot info(solution);
368            info.crash(doIdiot);
369          }
370#endif
371          solution.primal(1);
372        }
373      }
374      double time2 = cpuTime()-time1;
375      timeTaken += time2;
376      printf("Took %g seconds\n",time2);
377      // Test objective solution value
378      {
379        double soln = solution.objectiveValue();
380        CoinRelFltEq eq(objValueTol[m]);
381        std::cerr <<soln <<",  " <<objValue[m] <<" diff "<<
382          soln-objValue[m]<<std::endl;
383        if(!eq(soln,objValue[m]))
384          printf("** difference fails\n");
385      }
386    }
387    printf("Total time %g seconds\n",timeTaken);
388  }
389  else {
390    testingMessage( "***Skipped Testing on netlib    ***\n" );
391    testingMessage( "***use -netlib to test class***\n" );
392  }
393 
394  testingMessage( "All tests completed successfully\n" );
395  return 0;
396}
397
398 
399// Display message on stdout and stderr
400void testingMessage( const char * const msg )
401{
402  std::cerr <<msg;
403  //cout <<endl <<"*****************************************"
404  //     <<endl <<msg <<endl;
405}
406
407//--------------------------------------------------------------------------
408// test factorization methods and simplex method
409void
410ClpSimplexUnitTest(const std::string & mpsDir,
411                   const std::string & netlibDir)
412{
413 
414  CoinRelFltEq eq(0.000001);
415
416  {
417    ClpSimplex solution;
418 
419    // matrix data
420    //deliberate hiccup of 2 between 0 and 1
421    CoinBigIndex start[5]={0,4,7,8,9};
422    int length[5]={2,3,1,1,1};
423    int rows[11]={0,2,-1,-1,0,1,2,0,1,2};
424    double elements[11]={7.0,2.0,1.0e10,1.0e10,-2.0,1.0,-2.0,1,1,1};
425    CoinPackedMatrix matrix(true,3,5,8,elements,rows,start,length);
426   
427    // rim data
428    double objective[7]={-4.0,1.0,0.0,0.0,0.0,0.0,0.0};
429    double rowLower[5]={14.0,3.0,3.0,1.0e10,1.0e10};
430    double rowUpper[5]={14.0,3.0,3.0,-1.0e10,-1.0e10};
431    double colLower[7]={0.0,0.0,0.0,0.0,0.0,0.0,0.0};
432    double colUpper[7]={100.0,100.0,100.0,100.0,100.0,100.0,100.0};
433   
434    // basis 1
435    int rowBasis1[3]={-1,-1,-1};
436    int colBasis1[5]={1,1,-1,-1,1};
437    solution.loadProblem(matrix,colLower,colUpper,objective,
438                         rowLower,rowUpper);
439    int i;
440    solution.createStatus();
441    for (i=0;i<3;i++) {
442      if (rowBasis1[i]<0) {
443        solution.setRowStatus(i,ClpSimplex::atLowerBound);
444      } else {
445        solution.setRowStatus(i,ClpSimplex::basic);
446      }
447    }
448    for (i=0;i<5;i++) {
449      if (colBasis1[i]<0) {
450        solution.setColumnStatus(i,ClpSimplex::atLowerBound);
451      } else {
452        solution.setColumnStatus(i,ClpSimplex::basic);
453      }
454    }
455    solution.setLogLevel(3+4+8+16+32);
456    solution.primal();
457    for (i=0;i<3;i++) {
458      if (rowBasis1[i]<0) {
459        solution.setRowStatus(i,ClpSimplex::atLowerBound);
460      } else {
461        solution.setRowStatus(i,ClpSimplex::basic);
462      }
463    }
464    for (i=0;i<5;i++) {
465      if (colBasis1[i]<0) {
466        solution.setColumnStatus(i,ClpSimplex::atLowerBound);
467      } else {
468        solution.setColumnStatus(i,ClpSimplex::basic);
469      }
470    }
471    // intricate stuff does not work with scaling
472    solution.scaling(0);
473    assert(!solution.factorize ( ));
474    const double * colsol = solution.primalColumnSolution();
475    const double * rowsol = solution.primalRowSolution();
476    solution.getSolution(rowsol,colsol);
477    double colsol1[5]={20.0/7.0,3.0,0.0,0.0,23.0/7.0};
478    for (i=0;i<5;i++) {
479      assert(eq(colsol[i],colsol1[i]));
480    }
481    // now feed in again without actually doing factorization
482    ClpFactorization factorization2 = *solution.factorization();
483    ClpSimplex solution2 = solution;
484    solution2.setFactorization(factorization2);
485    solution2.createStatus();
486    for (i=0;i<3;i++) {
487      if (rowBasis1[i]<0) {
488        solution2.setRowStatus(i,ClpSimplex::atLowerBound);
489      } else {
490        solution2.setRowStatus(i,ClpSimplex::basic);
491      }
492    }
493    for (i=0;i<5;i++) {
494      if (colBasis1[i]<0) {
495        solution2.setColumnStatus(i,ClpSimplex::atLowerBound);
496      } else {
497        solution2.setColumnStatus(i,ClpSimplex::basic);
498      }
499    }
500    // intricate stuff does not work with scaling
501    solution2.scaling(0);
502    solution2.getSolution(rowsol,colsol);
503    colsol = solution2.primalColumnSolution();
504    rowsol = solution2.primalRowSolution();
505    for (i=0;i<5;i++) {
506      assert(eq(colsol[i],colsol1[i]));
507    }
508    solution2.setDualBound(0.1);
509    solution2.dual();
510    objective[2]=-1.0;
511    objective[3]=-0.5;
512    objective[4]=10.0;
513    solution.dual();
514    for (i=0;i<3;i++) {
515      rowLower[i]=-1.0e50;
516      colUpper[i+2]=0.0;
517    }
518    solution.setLogLevel(3);
519    solution.dual();
520    double rowObjective[]={1.0,0.5,-10.0};
521    solution.loadProblem(matrix,colLower,colUpper,objective,
522                         rowLower,rowUpper,rowObjective);
523    solution.dual();
524  }
525  {   
526    CoinMpsIO m;
527    std::string fn = mpsDir+"exmip1";
528    m.readMps(fn.c_str(),"mps");
529    ClpSimplex solution;
530    solution.loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
531                         m.getObjCoefficients(),
532                         m.getRowLower(),m.getRowUpper());
533    solution.dual();
534  }
535  // test steepest edge
536  {   
537    CoinMpsIO m;
538    std::string fn = netlibDir+"finnis";
539    m.readMps(fn.c_str(),"mps");
540    ClpModel model;
541    model.loadProblem(*m.getMatrixByCol(),m.getColLower(),
542                    m.getColUpper(),
543                    m.getObjCoefficients(),
544                    m.getRowLower(),m.getRowUpper());
545    ClpSimplex solution(model);
546
547    solution.scaling(1); 
548    solution.setDualBound(1.0e8);
549    //solution.factorization()->maximumPivots(1);
550    //solution.setLogLevel(3);
551    solution.setDualTolerance(1.0e-7);
552    // set objective sense,
553    ClpDualRowSteepest steep;
554    solution.setDualRowPivotAlgorithm(steep);
555    solution.setDblParam(ClpObjOffset,m.objectiveOffset());
556    solution.dual();
557  }
558  // test normal solution
559  {   
560    CoinMpsIO m;
561    std::string fn = netlibDir+"afiro";
562    m.readMps(fn.c_str(),"mps");
563    ClpSimplex solution;
564    ClpModel model;
565    // do twice - without and with scaling
566    int iPass;
567    for (iPass=0;iPass<2;iPass++) {
568      // explicit row objective for testing
569      int nr = m.getNumRows();
570      double * rowObj = new double[nr];
571      CoinFillN(rowObj,nr,0.0);
572      model.loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
573                      m.getObjCoefficients(),
574                      m.getRowLower(),m.getRowUpper(),rowObj);
575      delete [] rowObj;
576      solution = ClpSimplex(model);
577      if (iPass) {
578        solution.scaling();
579      }
580      solution.dual();
581      solution.dual();
582      // test optimal
583      assert (solution.status()==0);
584      int numberColumns = solution.numberColumns();
585      int numberRows = solution.numberRows();
586      CoinPackedVector colsol(numberColumns,solution.primalColumnSolution());
587      double * objective = solution.objective();
588      double objValue = colsol.dotProduct(objective);
589      CoinRelFltEq eq(1.0e-8);
590      assert(eq(objValue,-4.6475314286e+02));
591      double * lower = solution.columnLower();
592      double * upper = solution.columnUpper();
593      double * sol = solution.primalColumnSolution();
594      double * result = new double[numberColumns];
595      CoinFillN ( result, numberColumns,0.0);
596      solution.matrix()->transposeTimes(solution.dualRowSolution(), result);
597      int iRow , iColumn;
598      // see if feasible and dual feasible
599      for (iColumn=0;iColumn<numberColumns;iColumn++) {
600        double value = sol[iColumn];
601        assert(value<upper[iColumn]+1.0e-8);
602        assert(value>lower[iColumn]-1.0e-8);
603        value = objective[iColumn]-result[iColumn];
604        assert (value>-1.0e-5);
605        if (sol[iColumn]>1.0e-5)
606          assert (value<1.0e-5);
607      }
608      delete [] result;
609      result = new double[numberRows];
610      CoinFillN ( result, numberRows,0.0);
611      solution.matrix()->times(colsol, result);
612      lower = solution.rowLower();
613      upper = solution.rowUpper();
614      sol = solution.primalRowSolution();
615      for (iRow=0;iRow<numberRows;iRow++) {
616        double value = result[iRow];
617        assert(eq(value,sol[iRow]));
618        assert(value<upper[iRow]+1.0e-8);
619        assert(value>lower[iRow]-1.0e-8);
620      }
621      delete [] result;
622      // test row objective
623      double * rowObjective = solution.rowObjective();
624      CoinDisjointCopyN(solution.dualRowSolution(),numberRows,rowObjective);
625      CoinDisjointCopyN(solution.dualColumnSolution(),numberColumns,objective);
626      // this sets up all slack basis
627      solution.createStatus();
628      solution.dual();
629      CoinFillN(rowObjective,numberRows,0.0);
630      CoinDisjointCopyN(m.getObjCoefficients(),numberColumns,objective);
631      solution.dual();
632    }
633  }
634  // test unbounded
635  {   
636    CoinMpsIO m;
637    std::string fn = netlibDir+"brandy";
638    m.readMps(fn.c_str(),"mps");
639    ClpSimplex solution;
640    // do twice - without and with scaling
641    int iPass;
642    for (iPass=0;iPass<2;iPass++) {
643      solution.loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
644                      m.getObjCoefficients(),
645                      m.getRowLower(),m.getRowUpper());
646      if (iPass)
647        solution.scaling();
648      solution.setOptimizationDirection(-1);
649      // test unbounded and ray
650#ifdef DUAL
651      solution.setDualBound(100.0);
652      solution.dual();
653#else
654      solution.primal();
655#endif
656      assert (solution.status()==2);
657      int numberColumns = solution.numberColumns();
658      int numberRows = solution.numberRows();
659      double * lower = solution.columnLower();
660      double * upper = solution.columnUpper();
661      double * sol = solution.primalColumnSolution();
662      double * ray = solution.unboundedRay();
663      double * objective = solution.objective();
664      double objChange=0.0;
665      int iRow , iColumn;
666      // make sure feasible and columns form ray
667      for (iColumn=0;iColumn<numberColumns;iColumn++) {
668        double value = sol[iColumn];
669        assert(value<upper[iColumn]+1.0e-8);
670        assert(value>lower[iColumn]-1.0e-8);
671        value = ray[iColumn];
672        if (value>0.0)
673          assert(upper[iColumn]>1.0e30);
674        else if (value<0.0)
675          assert(lower[iColumn]<-1.0e30);
676        objChange += value*objective[iColumn];
677      }
678      // make sure increasing objective
679      assert(objChange>0.0);
680      double * result = new double[numberRows];
681      CoinFillN ( result, numberRows,0.0);
682      solution.matrix()->times(sol, result);
683      lower = solution.rowLower();
684      upper = solution.rowUpper();
685      sol = solution.primalRowSolution();
686      for (iRow=0;iRow<numberRows;iRow++) {
687        double value = result[iRow];
688        assert(eq(value,sol[iRow]));
689        assert(value<upper[iRow]+1.0e-8);
690        assert(value>lower[iRow]-1.0e-8);
691      }
692      CoinFillN ( result, numberRows,0.0);
693      solution.matrix()->times(ray, result);
694      // there may be small differences (especially if scaled)
695      for (iRow=0;iRow<numberRows;iRow++) {
696        double value = result[iRow];
697        if (value>1.0e-8)
698          assert(upper[iRow]>1.0e30);
699        else if (value<-1.0e-8)
700          assert(lower[iRow]<-1.0e30);
701      }
702      delete [] result;
703      delete [] ray;
704    }
705  }
706  // test infeasible
707  {   
708    CoinMpsIO m;
709    std::string fn = netlibDir+"brandy";
710    m.readMps(fn.c_str(),"mps");
711    ClpSimplex solution;
712    // do twice - without and with scaling
713    int iPass;
714    for (iPass=0;iPass<2;iPass++) {
715      solution.loadProblem(*m.getMatrixByCol(),m.getColLower(),m.getColUpper(),
716                      m.getObjCoefficients(),
717                      m.getRowLower(),m.getRowUpper());
718      if (iPass)
719        solution.scaling();
720      // test infeasible and ray
721      solution.columnUpper()[0]=0.0;
722#ifdef DUAL
723      solution.setDualBound(100.0);
724      solution.dual();
725#else
726      solution.primal();
727#endif
728      assert (solution.status()==1);
729      int numberColumns = solution.numberColumns();
730      int numberRows = solution.numberRows();
731      double * lower = solution.rowLower();
732      double * upper = solution.rowUpper();
733      double * ray = solution.infeasibilityRay();
734      assert(ray);
735      // construct proof of infeasibility
736      int iRow , iColumn;
737      double lo=0.0,up=0.0;
738      int nl=0,nu=0;
739      for (iRow=0;iRow<numberRows;iRow++) {
740        if (lower[iRow]>-1.0e20) {
741          lo += ray[iRow]*lower[iRow];
742        } else {
743          if (ray[iRow]>1.0e-8) 
744            nl++;
745        }
746        if (upper[iRow]<1.0e20) {
747          up += ray[iRow]*upper[iRow];
748        } else {
749          if (ray[iRow]>1.0e-8) 
750            nu++;
751        }
752      }
753      if (nl)
754        lo=-1.0e100;
755      if (nu)
756        up=1.0e100;
757      double * result = new double[numberColumns];
758      double lo2=0.0,up2=0.0;
759      CoinFillN ( result, numberColumns,0.0);
760      solution.matrix()->transposeTimes(ray, result);
761      lower = solution.columnLower();
762      upper = solution.columnUpper();
763      nl=nu=0;
764      for (iColumn=0;iColumn<numberColumns;iColumn++) {
765        if (result[iColumn]>1.0e-8) {
766          if (lower[iColumn]>-1.0e20)
767            lo2 += result[iColumn]*lower[iColumn];
768          else
769            nl++;
770          if (upper[iColumn]<1.0e20)
771            up2 += result[iColumn]*upper[iColumn];
772          else
773            nu++;
774        } else if (result[iColumn]<-1.0e-8) {
775          if (lower[iColumn]>-1.0e20)
776            up2 += result[iColumn]*lower[iColumn];
777          else
778            nu++;
779          if (upper[iColumn]<1.0e20)
780            lo2 += result[iColumn]*upper[iColumn];
781          else
782            nl++;
783        }
784      }
785      if (nl)
786        lo2=-1.0e100;
787      if (nu)
788        up2=1.0e100;
789      // make sure inconsistency
790      assert(lo2>up||up2<lo);
791      delete [] result;
792      delete [] ray;
793    }
794  }
795 
796  // test network
797  {   
798    std::string fn = mpsDir+"input.130";
799    int numberColumns;
800    int numberRows;
801   
802    FILE * fp = fopen(fn.c_str(),"r");
803
804    if (!fp) {
805      fprintf(stderr,"Unable to open file input.130 in mpsDir directory\n");
806      exit(1);
807    }
808    int problem;
809    char temp[100];
810    // read and skip
811    fscanf(fp,"%s",temp);
812    assert (!strcmp(temp,"BEGIN"));
813    fscanf(fp,"%*s %*s %d %d %*s %*s %d %*s",&problem, &numberRows, 
814           &numberColumns);
815    // scan down to SUPPLY
816    while (fgets(temp,100,fp)) {
817      if (!strncmp(temp,"SUPPLY",6))
818        break;
819    }
820    if (strncmp(temp,"SUPPLY",6)) {
821      fprintf(stderr,"Unable to find SUPPLY\n");
822      exit(2);
823    }
824    // get space for rhs
825    double * lower = new double[numberRows];
826    double * upper = new double[numberRows];
827    int i;
828    for (i=0;i<numberRows;i++) {
829      lower[i]=0.0;
830      upper[i]=0.0;
831    }
832    // ***** Remember to convert to C notation
833    while (fgets(temp,100,fp)) {
834      int row;
835      int value;
836      if (!strncmp(temp,"ARCS",4))
837        break;
838      sscanf(temp,"%d %d",&row,&value);
839      upper[row-1]=-value;
840      lower[row-1]=-value;
841    }
842    if (strncmp(temp,"ARCS",4)) {
843      fprintf(stderr,"Unable to find ARCS\n");
844      exit(2);
845    }
846    // number of columns may be underestimate
847    int * head = new int[2*numberColumns];
848    int * tail = new int[2*numberColumns];
849    int * ub = new int[2*numberColumns];
850    int * cost = new int[2*numberColumns];
851    // ***** Remember to convert to C notation
852    numberColumns=0;
853    while (fgets(temp,100,fp)) {
854      int iHead;
855      int iTail;
856      int iUb;
857      int iCost;
858      if (!strncmp(temp,"DEMAND",6))
859        break;
860      sscanf(temp,"%d %d %d %d",&iHead,&iTail,&iCost,&iUb);
861      iHead--;
862      iTail--;
863      head[numberColumns]=iHead;
864      tail[numberColumns]=iTail;
865      ub[numberColumns]=iUb;
866      cost[numberColumns]=iCost;
867      numberColumns++;
868    }
869    if (strncmp(temp,"DEMAND",6)) {
870      fprintf(stderr,"Unable to find DEMAND\n");
871      exit(2);
872    }
873    // ***** Remember to convert to C notation
874    while (fgets(temp,100,fp)) {
875      int row;
876      int value;
877      if (!strncmp(temp,"END",3))
878        break;
879      sscanf(temp,"%d %d",&row,&value);
880      upper[row-1]=value;
881      lower[row-1]=value;
882    }
883    if (strncmp(temp,"END",3)) {
884      fprintf(stderr,"Unable to find END\n");
885      exit(2);
886    }
887    printf("Problem %d has %d rows and %d columns\n",problem,
888           numberRows,numberColumns);
889    fclose(fp);
890    ClpSimplex  model;
891    // now build model
892   
893    double * objective =new double[numberColumns];
894    double * lowerColumn = new double[numberColumns];
895    double * upperColumn = new double[numberColumns];
896   
897    double * element = new double [2*numberColumns];
898    int * start = new int[numberColumns+1];
899    int * row = new int[2*numberColumns];
900    start[numberColumns]=2*numberColumns;
901    for (i=0;i<numberColumns;i++) {
902      start[i]=2*i;
903      element[2*i]=-1.0;
904      element[2*i+1]=1.0;
905      row[2*i]=head[i];
906      row[2*i+1]=tail[i];
907      lowerColumn[i]=0.0;
908      upperColumn[i]=ub[i];
909      objective[i]=cost[i];
910    }
911    // Create Packed Matrix
912    CoinPackedMatrix matrix;
913    int * lengths = NULL;
914    matrix.assignMatrix(true,numberRows,numberColumns,
915                        2*numberColumns,element,row,start,lengths);
916    // load model
917   
918    model.loadProblem(matrix,
919                      lowerColumn,upperColumn,objective,
920                      lower,upper);
921   
922    model.factorization()->maximumPivots(200+model.numberRows()/100);
923    model.createStatus();
924    double time1 = cpuTime();
925    model.dual();
926    std::cout<<"Network problem, ClpPackedMatrix took "<<cpuTime()-time1<<" seconds"<<std::endl;
927    ClpPlusMinusOneMatrix plusMinus(matrix);
928    assert (plusMinus.getIndices()); // would be zero if not +- one
929    model.loadProblem(plusMinus,
930                      lowerColumn,upperColumn,objective,
931                      lower,upper);
932   
933    model.factorization()->maximumPivots(200+model.numberRows()/100);
934    model.createStatus();
935    time1 = cpuTime();
936    model.dual();
937    std::cout<<"Network problem, ClpPlusMinusOneMatrix took "<<cpuTime()-time1<<" seconds"<<std::endl;
938    ClpNetworkMatrix network(numberColumns,head,tail);
939    model.loadProblem(network,
940                      lowerColumn,upperColumn,objective,
941                      lower,upper);
942   
943    model.factorization()->maximumPivots(200+model.numberRows()/100);
944    model.createStatus();
945    time1 = cpuTime();
946    model.dual();
947    std::cout<<"Network problem, ClpNetworkMatrix took "<<cpuTime()-time1<<" seconds"<<std::endl;
948    delete [] lower;
949    delete [] upper;
950    delete [] head;
951    delete [] tail;
952    delete [] ub;
953    delete [] cost;
954    delete [] objective;
955    delete [] lowerColumn;
956    delete [] upperColumn;
957  }
958 
959}
Note: See TracBrowser for help on using the repository browser.