test/lp_test.cc
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 732 bb70ad62c95f
parent 622 20dac2104519
child 766 2eebc8f7dca5
permissions -rw-r--r--
Fix critical bug in preflow (#372)

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