test/lp_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Tue, 15 Mar 2011 19:32:21 +0100
changeset 1047 ddd3c0d3d9bf
parent 674 20dac2104519
child 1092 2eebc8f7dca5
permissions -rw-r--r--
Implement the scaling Price Refinement heuristic in CostScaling (#417)
instead of Early Termination.

These two heuristics are similar, but the newer one is faster
and not only makes it possible to skip some epsilon phases, but
it can improve the performance of the other phases, as well.
deba@481
     1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
deba@481
     2
 *
deba@481
     3
 * This file is a part of LEMON, a generic C++ optimization library.
deba@481
     4
 *
deba@598
     5
 * Copyright (C) 2003-2009
deba@481
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
deba@481
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@481
     8
 *
deba@481
     9
 * Permission to use, modify and distribute this software is granted
deba@481
    10
 * provided that this copyright notice appears in all copies. For
deba@481
    11
 * precise terms see the accompanying LICENSE file.
deba@481
    12
 *
deba@481
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@481
    14
 * express or implied, and with no claim as to its suitability for any
deba@481
    15
 * purpose.
deba@481
    16
 *
deba@481
    17
 */
deba@481
    18
deba@481
    19
#include <sstream>
deba@481
    20
#include <lemon/lp_skeleton.h>
deba@481
    21
#include "test_tools.h"
deba@481
    22
#include <lemon/tolerance.h>
deba@481
    23
deba@481
    24
#include <lemon/config.h>
deba@481
    25
ladanyi@674
    26
#ifdef LEMON_HAVE_GLPK
alpar@484
    27
#include <lemon/glpk.h>
deba@481
    28
#endif
deba@481
    29
ladanyi@674
    30
#ifdef LEMON_HAVE_CPLEX
alpar@484
    31
#include <lemon/cplex.h>
deba@481
    32
#endif
deba@481
    33
ladanyi@674
    34
#ifdef LEMON_HAVE_SOPLEX
alpar@484
    35
#include <lemon/soplex.h>
deba@481
    36
#endif
deba@481
    37
ladanyi@674
    38
#ifdef LEMON_HAVE_CLP
alpar@484
    39
#include <lemon/clp.h>
deba@482
    40
#endif
deba@482
    41
deba@481
    42
using namespace lemon;
deba@481
    43
deba@482
    44
void lpTest(LpSolver& lp)
deba@481
    45
{
deba@481
    46
deba@482
    47
  typedef LpSolver LP;
deba@481
    48
deba@481
    49
  std::vector<LP::Col> x(10);
deba@481
    50
  //  for(int i=0;i<10;i++) x.push_back(lp.addCol());
deba@481
    51
  lp.addColSet(x);
deba@481
    52
  lp.colLowerBound(x,1);
deba@481
    53
  lp.colUpperBound(x,1);
deba@481
    54
  lp.colBounds(x,1,2);
deba@481
    55
deba@481
    56
  std::vector<LP::Col> y(10);
deba@481
    57
  lp.addColSet(y);
deba@481
    58
deba@481
    59
  lp.colLowerBound(y,1);
deba@481
    60
  lp.colUpperBound(y,1);
deba@481
    61
  lp.colBounds(y,1,2);
deba@481
    62
deba@481
    63
  std::map<int,LP::Col> z;
deba@481
    64
deba@481
    65
  z.insert(std::make_pair(12,INVALID));
deba@481
    66
  z.insert(std::make_pair(2,INVALID));
deba@481
    67
  z.insert(std::make_pair(7,INVALID));
deba@481
    68
  z.insert(std::make_pair(5,INVALID));
deba@481
    69
deba@481
    70
  lp.addColSet(z);
deba@481
    71
deba@481
    72
  lp.colLowerBound(z,1);
deba@481
    73
  lp.colUpperBound(z,1);
deba@481
    74
  lp.colBounds(z,1,2);
deba@481
    75
deba@481
    76
  {
deba@481
    77
    LP::Expr e,f,g;
deba@481
    78
    LP::Col p1,p2,p3,p4,p5;
deba@481
    79
    LP::Constr c;
deba@481
    80
deba@481
    81
    p1=lp.addCol();
deba@481
    82
    p2=lp.addCol();
deba@481
    83
    p3=lp.addCol();
deba@481
    84
    p4=lp.addCol();
deba@481
    85
    p5=lp.addCol();
deba@481
    86
deba@481
    87
    e[p1]=2;
deba@482
    88
    *e=12;
deba@481
    89
    e[p1]+=2;
deba@482
    90
    *e+=12;
deba@481
    91
    e[p1]-=2;
deba@482
    92
    *e-=12;
deba@481
    93
deba@481
    94
    e=2;
deba@481
    95
    e=2.2;
deba@481
    96
    e=p1;
deba@481
    97
    e=f;
deba@481
    98
deba@481
    99
    e+=2;
deba@481
   100
    e+=2.2;
deba@481
   101
    e+=p1;
deba@481
   102
    e+=f;
deba@481
   103
deba@481
   104
    e-=2;
deba@481
   105
    e-=2.2;
deba@481
   106
    e-=p1;
deba@481
   107
    e-=f;
deba@481
   108
deba@481
   109
    e*=2;
deba@481
   110
    e*=2.2;
deba@481
   111
    e/=2;
deba@481
   112
    e/=2.2;
deba@481
   113
deba@481
   114
    e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+
deba@481
   115
       (f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+
deba@481
   116
       (f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+
deba@481
   117
       2.2*f+f*2.2+f/2.2+
deba@481
   118
       2*f+f*2+f/2+
deba@481
   119
       2.2*p1+p1*2.2+p1/2.2+
deba@481
   120
       2*p1+p1*2+p1/2
deba@481
   121
       );
deba@481
   122
deba@481
   123
deba@481
   124
    c = (e  <= f  );
deba@481
   125
    c = (e  <= 2.2);
deba@481
   126
    c = (e  <= 2  );
deba@481
   127
    c = (e  <= p1 );
deba@481
   128
    c = (2.2<= f  );
deba@481
   129
    c = (2  <= f  );
deba@481
   130
    c = (p1 <= f  );
deba@481
   131
    c = (p1 <= p2 );
deba@481
   132
    c = (p1 <= 2.2);
deba@481
   133
    c = (p1 <= 2  );
deba@481
   134
    c = (2.2<= p2 );
deba@481
   135
    c = (2  <= p2 );
deba@481
   136
deba@481
   137
    c = (e  >= f  );
deba@481
   138
    c = (e  >= 2.2);
deba@481
   139
    c = (e  >= 2  );
deba@481
   140
    c = (e  >= p1 );
deba@481
   141
    c = (2.2>= f  );
deba@481
   142
    c = (2  >= f  );
deba@481
   143
    c = (p1 >= f  );
deba@481
   144
    c = (p1 >= p2 );
deba@481
   145
    c = (p1 >= 2.2);
deba@481
   146
    c = (p1 >= 2  );
deba@481
   147
    c = (2.2>= p2 );
deba@481
   148
    c = (2  >= p2 );
deba@481
   149
deba@481
   150
    c = (e  == f  );
deba@481
   151
    c = (e  == 2.2);
deba@481
   152
    c = (e  == 2  );
deba@481
   153
    c = (e  == p1 );
deba@481
   154
    c = (2.2== f  );
deba@481
   155
    c = (2  == f  );
deba@481
   156
    c = (p1 == f  );
deba@481
   157
    //c = (p1 == p2 );
deba@481
   158
    c = (p1 == 2.2);
deba@481
   159
    c = (p1 == 2  );
deba@481
   160
    c = (2.2== p2 );
deba@481
   161
    c = (2  == p2 );
deba@481
   162
alpar@483
   163
    c = ((2 <= e) <= 3);
alpar@483
   164
    c = ((2 <= p1) <= 3);
deba@481
   165
alpar@483
   166
    c = ((2 >= e) >= 3);
alpar@483
   167
    c = ((2 >= p1) >= 3);
deba@481
   168
deba@481
   169
    e[x[3]]=2;
deba@481
   170
    e[x[3]]=4;
deba@481
   171
    e[x[3]]=1;
deba@482
   172
    *e=12;
deba@481
   173
deba@482
   174
    lp.addRow(-LP::INF,e,23);
deba@482
   175
    lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23);
deba@482
   176
    lp.addRow(-LP::INF,3.0*(x[1]+x[2]*2-5*x[3]+12-x[4]/3)+2*x[4]-4,23);
deba@481
   177
deba@481
   178
    lp.addRow(x[1]+x[3]<=x[5]-3);
alpar@483
   179
    lp.addRow((-7<=x[1]+x[3]-12)<=3);
deba@481
   180
    lp.addRow(x[1]<=x[5]);
deba@481
   181
deba@481
   182
    std::ostringstream buf;
deba@481
   183
deba@481
   184
deba@481
   185
    e=((p1+p2)+(p1-0.99*p2));
deba@481
   186
    //e.prettyPrint(std::cout);
deba@481
   187
    //(e<=2).prettyPrint(std::cout);
deba@481
   188
    double tolerance=0.001;
deba@481
   189
    e.simplify(tolerance);
deba@481
   190
    buf << "Coeff. of p2 should be 0.01";
deba@481
   191
    check(e[p2]>0, buf.str());
deba@481
   192
deba@481
   193
    tolerance=0.02;
deba@481
   194
    e.simplify(tolerance);
deba@481
   195
    buf << "Coeff. of p2 should be 0";
deba@482
   196
    check(const_cast<const LpSolver::Expr&>(e)[p2]==0, buf.str());
deba@481
   197
alpar@587
   198
    //Test for clone/new
alpar@587
   199
    LP* lpnew = lp.newSolver();
alpar@587
   200
    LP* lpclone = lp.cloneSolver();
alpar@587
   201
    delete lpnew;
alpar@587
   202
    delete lpclone;
deba@481
   203
deba@481
   204
  }
deba@481
   205
deba@481
   206
  {
deba@481
   207
    LP::DualExpr e,f,g;
deba@481
   208
    LP::Row p1 = INVALID, p2 = INVALID, p3 = INVALID,
deba@481
   209
      p4 = INVALID, p5 = INVALID;
deba@481
   210
deba@481
   211
    e[p1]=2;
deba@481
   212
    e[p1]+=2;
deba@481
   213
    e[p1]-=2;
deba@481
   214
deba@481
   215
    e=p1;
deba@481
   216
    e=f;
deba@481
   217
deba@481
   218
    e+=p1;
deba@481
   219
    e+=f;
deba@481
   220
deba@481
   221
    e-=p1;
deba@481
   222
    e-=f;
deba@481
   223
deba@481
   224
    e*=2;
deba@481
   225
    e*=2.2;
deba@481
   226
    e/=2;
deba@481
   227
    e/=2.2;
deba@481
   228
deba@481
   229
    e=((p1+p2)+(p1-p2)+
deba@481
   230
       (p1+f)+(f+p1)+(f+g)+
deba@481
   231
       (p1-f)+(f-p1)+(f-g)+
deba@481
   232
       2.2*f+f*2.2+f/2.2+
deba@481
   233
       2*f+f*2+f/2+
deba@481
   234
       2.2*p1+p1*2.2+p1/2.2+
deba@481
   235
       2*p1+p1*2+p1/2
deba@481
   236
       );
deba@481
   237
  }
deba@481
   238
deba@481
   239
}
deba@481
   240
deba@482
   241
void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat,
deba@481
   242
                   double exp_opt) {
deba@481
   243
  using std::string;
deba@481
   244
  lp.solve();
deba@482
   245
deba@481
   246
  std::ostringstream buf;
deba@482
   247
  buf << "PrimalType should be: " << int(stat) << int(lp.primalType());
deba@481
   248
deba@482
   249
  check(lp.primalType()==stat, buf.str());
deba@481
   250
deba@482
   251
  if (stat ==  LpSolver::OPTIMAL) {
deba@481
   252
    std::ostringstream sbuf;
alpar@587
   253
    sbuf << "Wrong optimal value (" << lp.primal() <<") with "
alpar@587
   254
         << lp.solverName() <<"\n     the right optimum is " << exp_opt;
deba@482
   255
    check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str());
deba@481
   256
  }
deba@481
   257
}
deba@481
   258
deba@482
   259
void aTest(LpSolver & lp)
deba@481
   260
{
deba@482
   261
  typedef LpSolver LP;
deba@481
   262
deba@481
   263
 //The following example is very simple
deba@481
   264
deba@482
   265
  typedef LpSolver::Row Row;
deba@482
   266
  typedef LpSolver::Col Col;
deba@481
   267
deba@481
   268
deba@481
   269
  Col x1 = lp.addCol();
deba@481
   270
  Col x2 = lp.addCol();
deba@481
   271
deba@481
   272
deba@481
   273
  //Constraints
deba@482
   274
  Row upright=lp.addRow(x1+2*x2 <=1);
deba@481
   275
  lp.addRow(x1+x2 >=-1);
deba@481
   276
  lp.addRow(x1-x2 <=1);
deba@481
   277
  lp.addRow(x1-x2 >=-1);
deba@481
   278
  //Nonnegativity of the variables
deba@481
   279
  lp.colLowerBound(x1, 0);
deba@481
   280
  lp.colLowerBound(x2, 0);
deba@481
   281
  //Objective function
deba@481
   282
  lp.obj(x1+x2);
deba@481
   283
deba@482
   284
  lp.sense(lp.MAX);
deba@481
   285
deba@481
   286
  //Testing the problem retrieving routines
deba@481
   287
  check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!");
deba@482
   288
  check(lp.sense() == lp.MAX,"This is a maximization!");
deba@481
   289
  check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!");
deba@482
   290
  check(lp.colLowerBound(x1)==0,
deba@482
   291
        "The lower bound for variable x1 should be 0.");
deba@482
   292
  check(lp.colUpperBound(x1)==LpSolver::INF,
deba@482
   293
        "The upper bound for variable x1 should be infty.");
deba@482
   294
  check(lp.rowLowerBound(upright) == -LpSolver::INF,
deba@482
   295
        "The lower bound for the first row should be -infty.");
deba@482
   296
  check(lp.rowUpperBound(upright)==1,
deba@482
   297
        "The upper bound for the first row should be 1.");
deba@482
   298
  LpSolver::Expr e = lp.row(upright);
deba@482
   299
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   300
  check(e[x2] == 2, "The second coefficient should 1.");
deba@481
   301
deba@482
   302
  lp.row(upright, x1+x2 <=1);
deba@482
   303
  e = lp.row(upright);
deba@482
   304
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   305
  check(e[x2] == 1, "The second coefficient should 1.");
deba@482
   306
deba@482
   307
  LpSolver::DualExpr de = lp.col(x1);
deba@481
   308
  check(  de[upright] == 1, "The first coefficient should 1.");
deba@481
   309
deba@482
   310
  LpSolver* clp = lp.cloneSolver();
deba@481
   311
deba@481
   312
  //Testing the problem retrieving routines
deba@481
   313
  check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!");
deba@482
   314
  check(clp->sense() == clp->MAX,"This is a maximization!");
deba@481
   315
  check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!");
deba@481
   316
  //  std::cout<<lp.colLowerBound(x1)<<std::endl;
deba@482
   317
  check(clp->colLowerBound(x1)==0,
deba@482
   318
        "The lower bound for variable x1 should be 0.");
deba@482
   319
  check(clp->colUpperBound(x1)==LpSolver::INF,
deba@482
   320
        "The upper bound for variable x1 should be infty.");
deba@481
   321
deba@482
   322
  check(lp.rowLowerBound(upright)==-LpSolver::INF,
deba@482
   323
        "The lower bound for the first row should be -infty.");
deba@482
   324
  check(lp.rowUpperBound(upright)==1,
deba@482
   325
        "The upper bound for the first row should be 1.");
deba@481
   326
  e = clp->row(upright);
deba@482
   327
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   328
  check(e[x2] == 1, "The second coefficient should 1.");
deba@481
   329
deba@481
   330
  de = clp->col(x1);
deba@482
   331
  check(de[upright] == 1, "The first coefficient should 1.");
deba@481
   332
deba@481
   333
  delete clp;
deba@481
   334
deba@481
   335
  //Maximization of x1+x2
deba@481
   336
  //over the triangle with vertices (0,0) (0,1) (1,0)
deba@481
   337
  double expected_opt=1;
deba@482
   338
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   339
deba@481
   340
  //Minimization
deba@482
   341
  lp.sense(lp.MIN);
deba@481
   342
  expected_opt=0;
deba@482
   343
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   344
deba@481
   345
  //Vertex (-1,0) instead of (0,0)
deba@482
   346
  lp.colLowerBound(x1, -LpSolver::INF);
deba@481
   347
  expected_opt=-1;
deba@482
   348
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   349
deba@481
   350
  //Erase one constraint and return to maximization
deba@482
   351
  lp.erase(upright);
deba@482
   352
  lp.sense(lp.MAX);
deba@482
   353
  expected_opt=LpSolver::INF;
deba@482
   354
  solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt);
deba@481
   355
deba@481
   356
  //Infeasibilty
deba@481
   357
  lp.addRow(x1+x2 <=-2);
deba@482
   358
  solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt);
deba@481
   359
deba@481
   360
}
deba@481
   361
alpar@587
   362
template<class LP>
alpar@587
   363
void cloneTest()
alpar@587
   364
{
alpar@587
   365
  //Test for clone/new
deba@598
   366
alpar@587
   367
  LP* lp = new LP();
alpar@587
   368
  LP* lpnew = lp->newSolver();
alpar@587
   369
  LP* lpclone = lp->cloneSolver();
alpar@587
   370
  delete lp;
alpar@587
   371
  delete lpnew;
alpar@587
   372
  delete lpclone;
alpar@587
   373
}
alpar@587
   374
deba@481
   375
int main()
deba@481
   376
{
deba@481
   377
  LpSkeleton lp_skel;
deba@481
   378
  lpTest(lp_skel);
deba@481
   379
ladanyi@674
   380
#ifdef LEMON_HAVE_GLPK
deba@482
   381
  {
alpar@485
   382
    GlpkLp lp_glpk1,lp_glpk2;
deba@482
   383
    lpTest(lp_glpk1);
deba@482
   384
    aTest(lp_glpk2);
alpar@587
   385
    cloneTest<GlpkLp>();
deba@482
   386
  }
deba@481
   387
#endif
deba@481
   388
ladanyi@674
   389
#ifdef LEMON_HAVE_CPLEX
deba@482
   390
  try {
alpar@485
   391
    CplexLp lp_cplex1,lp_cplex2;
deba@482
   392
    lpTest(lp_cplex1);
deba@482
   393
    aTest(lp_cplex2);
deba@598
   394
    cloneTest<CplexLp>();
deba@482
   395
  } catch (CplexEnv::LicenseError& error) {
deba@482
   396
    check(false, error.what());
deba@482
   397
  }
deba@481
   398
#endif
deba@481
   399
ladanyi@674
   400
#ifdef LEMON_HAVE_SOPLEX
deba@482
   401
  {
alpar@485
   402
    SoplexLp lp_soplex1,lp_soplex2;
deba@482
   403
    lpTest(lp_soplex1);
deba@482
   404
    aTest(lp_soplex2);
alpar@587
   405
    cloneTest<SoplexLp>();
deba@482
   406
  }
deba@482
   407
#endif
deba@482
   408
ladanyi@674
   409
#ifdef LEMON_HAVE_CLP
deba@482
   410
  {
alpar@485
   411
    ClpLp lp_clp1,lp_clp2;
deba@482
   412
    lpTest(lp_clp1);
deba@482
   413
    aTest(lp_clp2);
alpar@587
   414
    cloneTest<ClpLp>();
deba@482
   415
  }
deba@481
   416
#endif
deba@481
   417
deba@481
   418
  return 0;
deba@481
   419
}