test/lp_test.cc
author Peter Kovacs <kpeter@inf.elte.hu>
Fri, 17 Apr 2009 18:04:36 +0200
changeset 656 e6927fe719e6
parent 484 08d495d48089
child 584 0fec6a017ead
child 587 9db62975c32b
permissions -rw-r--r--
Support >= and <= constraints in NetworkSimplex (#219, #234)

By default the same inequality constraints are supported as by
Circulation (the GEQ form), but the LEQ form can also be selected
using the problemType() function.

The documentation of the min. cost flow module is reworked and
extended with important notes and explanations about the different
variants of the problem and about the dual solution and optimality
conditions.
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@481
     5
 * Copyright (C) 2003-2008
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
#ifdef HAVE_CONFIG_H
deba@481
    25
#include <lemon/config.h>
deba@481
    26
#endif
deba@481
    27
deba@481
    28
#ifdef HAVE_GLPK
alpar@484
    29
#include <lemon/glpk.h>
deba@481
    30
#endif
deba@481
    31
deba@481
    32
#ifdef HAVE_CPLEX
alpar@484
    33
#include <lemon/cplex.h>
deba@481
    34
#endif
deba@481
    35
deba@481
    36
#ifdef HAVE_SOPLEX
alpar@484
    37
#include <lemon/soplex.h>
deba@481
    38
#endif
deba@481
    39
deba@482
    40
#ifdef HAVE_CLP
alpar@484
    41
#include <lemon/clp.h>
deba@482
    42
#endif
deba@482
    43
deba@481
    44
using namespace lemon;
deba@481
    45
deba@482
    46
void lpTest(LpSolver& lp)
deba@481
    47
{
deba@481
    48
deba@482
    49
  typedef LpSolver LP;
deba@481
    50
deba@481
    51
  std::vector<LP::Col> x(10);
deba@481
    52
  //  for(int i=0;i<10;i++) x.push_back(lp.addCol());
deba@481
    53
  lp.addColSet(x);
deba@481
    54
  lp.colLowerBound(x,1);
deba@481
    55
  lp.colUpperBound(x,1);
deba@481
    56
  lp.colBounds(x,1,2);
deba@481
    57
deba@481
    58
  std::vector<LP::Col> y(10);
deba@481
    59
  lp.addColSet(y);
deba@481
    60
deba@481
    61
  lp.colLowerBound(y,1);
deba@481
    62
  lp.colUpperBound(y,1);
deba@481
    63
  lp.colBounds(y,1,2);
deba@481
    64
deba@481
    65
  std::map<int,LP::Col> z;
deba@481
    66
deba@481
    67
  z.insert(std::make_pair(12,INVALID));
deba@481
    68
  z.insert(std::make_pair(2,INVALID));
deba@481
    69
  z.insert(std::make_pair(7,INVALID));
deba@481
    70
  z.insert(std::make_pair(5,INVALID));
deba@481
    71
deba@481
    72
  lp.addColSet(z);
deba@481
    73
deba@481
    74
  lp.colLowerBound(z,1);
deba@481
    75
  lp.colUpperBound(z,1);
deba@481
    76
  lp.colBounds(z,1,2);
deba@481
    77
deba@481
    78
  {
deba@481
    79
    LP::Expr e,f,g;
deba@481
    80
    LP::Col p1,p2,p3,p4,p5;
deba@481
    81
    LP::Constr c;
deba@481
    82
deba@481
    83
    p1=lp.addCol();
deba@481
    84
    p2=lp.addCol();
deba@481
    85
    p3=lp.addCol();
deba@481
    86
    p4=lp.addCol();
deba@481
    87
    p5=lp.addCol();
deba@481
    88
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
    e[p1]-=2;
deba@482
    94
    *e-=12;
deba@481
    95
deba@481
    96
    e=2;
deba@481
    97
    e=2.2;
deba@481
    98
    e=p1;
deba@481
    99
    e=f;
deba@481
   100
deba@481
   101
    e+=2;
deba@481
   102
    e+=2.2;
deba@481
   103
    e+=p1;
deba@481
   104
    e+=f;
deba@481
   105
deba@481
   106
    e-=2;
deba@481
   107
    e-=2.2;
deba@481
   108
    e-=p1;
deba@481
   109
    e-=f;
deba@481
   110
deba@481
   111
    e*=2;
deba@481
   112
    e*=2.2;
deba@481
   113
    e/=2;
deba@481
   114
    e/=2.2;
deba@481
   115
deba@481
   116
    e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+
deba@481
   117
       (f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+
deba@481
   118
       (f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+
deba@481
   119
       2.2*f+f*2.2+f/2.2+
deba@481
   120
       2*f+f*2+f/2+
deba@481
   121
       2.2*p1+p1*2.2+p1/2.2+
deba@481
   122
       2*p1+p1*2+p1/2
deba@481
   123
       );
deba@481
   124
deba@481
   125
deba@481
   126
    c = (e  <= f  );
deba@481
   127
    c = (e  <= 2.2);
deba@481
   128
    c = (e  <= 2  );
deba@481
   129
    c = (e  <= p1 );
deba@481
   130
    c = (2.2<= f  );
deba@481
   131
    c = (2  <= f  );
deba@481
   132
    c = (p1 <= f  );
deba@481
   133
    c = (p1 <= p2 );
deba@481
   134
    c = (p1 <= 2.2);
deba@481
   135
    c = (p1 <= 2  );
deba@481
   136
    c = (2.2<= p2 );
deba@481
   137
    c = (2  <= p2 );
deba@481
   138
deba@481
   139
    c = (e  >= f  );
deba@481
   140
    c = (e  >= 2.2);
deba@481
   141
    c = (e  >= 2  );
deba@481
   142
    c = (e  >= p1 );
deba@481
   143
    c = (2.2>= f  );
deba@481
   144
    c = (2  >= f  );
deba@481
   145
    c = (p1 >= f  );
deba@481
   146
    c = (p1 >= p2 );
deba@481
   147
    c = (p1 >= 2.2);
deba@481
   148
    c = (p1 >= 2  );
deba@481
   149
    c = (2.2>= p2 );
deba@481
   150
    c = (2  >= p2 );
deba@481
   151
deba@481
   152
    c = (e  == f  );
deba@481
   153
    c = (e  == 2.2);
deba@481
   154
    c = (e  == 2  );
deba@481
   155
    c = (e  == p1 );
deba@481
   156
    c = (2.2== f  );
deba@481
   157
    c = (2  == f  );
deba@481
   158
    c = (p1 == f  );
deba@481
   159
    //c = (p1 == p2 );
deba@481
   160
    c = (p1 == 2.2);
deba@481
   161
    c = (p1 == 2  );
deba@481
   162
    c = (2.2== p2 );
deba@481
   163
    c = (2  == p2 );
deba@481
   164
alpar@483
   165
    c = ((2 <= e) <= 3);
alpar@483
   166
    c = ((2 <= p1) <= 3);
deba@481
   167
alpar@483
   168
    c = ((2 >= e) >= 3);
alpar@483
   169
    c = ((2 >= p1) >= 3);
deba@481
   170
deba@481
   171
    e[x[3]]=2;
deba@481
   172
    e[x[3]]=4;
deba@481
   173
    e[x[3]]=1;
deba@482
   174
    *e=12;
deba@481
   175
deba@482
   176
    lp.addRow(-LP::INF,e,23);
deba@482
   177
    lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23);
deba@482
   178
    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
   179
deba@481
   180
    lp.addRow(x[1]+x[3]<=x[5]-3);
alpar@483
   181
    lp.addRow((-7<=x[1]+x[3]-12)<=3);
deba@481
   182
    lp.addRow(x[1]<=x[5]);
deba@481
   183
deba@481
   184
    std::ostringstream buf;
deba@481
   185
deba@481
   186
deba@481
   187
    e=((p1+p2)+(p1-0.99*p2));
deba@481
   188
    //e.prettyPrint(std::cout);
deba@481
   189
    //(e<=2).prettyPrint(std::cout);
deba@481
   190
    double tolerance=0.001;
deba@481
   191
    e.simplify(tolerance);
deba@481
   192
    buf << "Coeff. of p2 should be 0.01";
deba@481
   193
    check(e[p2]>0, buf.str());
deba@481
   194
deba@481
   195
    tolerance=0.02;
deba@481
   196
    e.simplify(tolerance);
deba@481
   197
    buf << "Coeff. of p2 should be 0";
deba@482
   198
    check(const_cast<const LpSolver::Expr&>(e)[p2]==0, buf.str());
deba@481
   199
deba@481
   200
deba@481
   201
  }
deba@481
   202
deba@481
   203
  {
deba@481
   204
    LP::DualExpr e,f,g;
deba@481
   205
    LP::Row p1 = INVALID, p2 = INVALID, p3 = INVALID,
deba@481
   206
      p4 = INVALID, p5 = INVALID;
deba@481
   207
deba@481
   208
    e[p1]=2;
deba@481
   209
    e[p1]+=2;
deba@481
   210
    e[p1]-=2;
deba@481
   211
deba@481
   212
    e=p1;
deba@481
   213
    e=f;
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*=2;
deba@481
   222
    e*=2.2;
deba@481
   223
    e/=2;
deba@481
   224
    e/=2.2;
deba@481
   225
deba@481
   226
    e=((p1+p2)+(p1-p2)+
deba@481
   227
       (p1+f)+(f+p1)+(f+g)+
deba@481
   228
       (p1-f)+(f-p1)+(f-g)+
deba@481
   229
       2.2*f+f*2.2+f/2.2+
deba@481
   230
       2*f+f*2+f/2+
deba@481
   231
       2.2*p1+p1*2.2+p1/2.2+
deba@481
   232
       2*p1+p1*2+p1/2
deba@481
   233
       );
deba@481
   234
  }
deba@481
   235
deba@481
   236
}
deba@481
   237
deba@482
   238
void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat,
deba@481
   239
                   double exp_opt) {
deba@481
   240
  using std::string;
deba@481
   241
  lp.solve();
deba@482
   242
deba@481
   243
  std::ostringstream buf;
deba@482
   244
  buf << "PrimalType should be: " << int(stat) << int(lp.primalType());
deba@481
   245
deba@482
   246
  check(lp.primalType()==stat, buf.str());
deba@481
   247
deba@482
   248
  if (stat ==  LpSolver::OPTIMAL) {
deba@481
   249
    std::ostringstream sbuf;
deba@481
   250
    sbuf << "Wrong optimal value: the right optimum is " << exp_opt;
deba@482
   251
    check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str());
deba@481
   252
  }
deba@481
   253
}
deba@481
   254
deba@482
   255
void aTest(LpSolver & lp)
deba@481
   256
{
deba@482
   257
  typedef LpSolver LP;
deba@481
   258
deba@481
   259
 //The following example is very simple
deba@481
   260
deba@482
   261
  typedef LpSolver::Row Row;
deba@482
   262
  typedef LpSolver::Col Col;
deba@481
   263
deba@481
   264
deba@481
   265
  Col x1 = lp.addCol();
deba@481
   266
  Col x2 = lp.addCol();
deba@481
   267
deba@481
   268
deba@481
   269
  //Constraints
deba@482
   270
  Row upright=lp.addRow(x1+2*x2 <=1);
deba@481
   271
  lp.addRow(x1+x2 >=-1);
deba@481
   272
  lp.addRow(x1-x2 <=1);
deba@481
   273
  lp.addRow(x1-x2 >=-1);
deba@481
   274
  //Nonnegativity of the variables
deba@481
   275
  lp.colLowerBound(x1, 0);
deba@481
   276
  lp.colLowerBound(x2, 0);
deba@481
   277
  //Objective function
deba@481
   278
  lp.obj(x1+x2);
deba@481
   279
deba@482
   280
  lp.sense(lp.MAX);
deba@481
   281
deba@481
   282
  //Testing the problem retrieving routines
deba@481
   283
  check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!");
deba@482
   284
  check(lp.sense() == lp.MAX,"This is a maximization!");
deba@481
   285
  check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!");
deba@482
   286
  check(lp.colLowerBound(x1)==0,
deba@482
   287
        "The lower bound for variable x1 should be 0.");
deba@482
   288
  check(lp.colUpperBound(x1)==LpSolver::INF,
deba@482
   289
        "The upper bound for variable x1 should be infty.");
deba@482
   290
  check(lp.rowLowerBound(upright) == -LpSolver::INF,
deba@482
   291
        "The lower bound for the first row should be -infty.");
deba@482
   292
  check(lp.rowUpperBound(upright)==1,
deba@482
   293
        "The upper bound for the first row should be 1.");
deba@482
   294
  LpSolver::Expr e = lp.row(upright);
deba@482
   295
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   296
  check(e[x2] == 2, "The second coefficient should 1.");
deba@481
   297
deba@482
   298
  lp.row(upright, x1+x2 <=1);
deba@482
   299
  e = lp.row(upright);
deba@482
   300
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   301
  check(e[x2] == 1, "The second coefficient should 1.");
deba@482
   302
deba@482
   303
  LpSolver::DualExpr de = lp.col(x1);
deba@481
   304
  check(  de[upright] == 1, "The first coefficient should 1.");
deba@481
   305
deba@482
   306
  LpSolver* clp = lp.cloneSolver();
deba@481
   307
deba@481
   308
  //Testing the problem retrieving routines
deba@481
   309
  check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!");
deba@482
   310
  check(clp->sense() == clp->MAX,"This is a maximization!");
deba@481
   311
  check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!");
deba@481
   312
  //  std::cout<<lp.colLowerBound(x1)<<std::endl;
deba@482
   313
  check(clp->colLowerBound(x1)==0,
deba@482
   314
        "The lower bound for variable x1 should be 0.");
deba@482
   315
  check(clp->colUpperBound(x1)==LpSolver::INF,
deba@482
   316
        "The upper bound for variable x1 should be infty.");
deba@481
   317
deba@482
   318
  check(lp.rowLowerBound(upright)==-LpSolver::INF,
deba@482
   319
        "The lower bound for the first row should be -infty.");
deba@482
   320
  check(lp.rowUpperBound(upright)==1,
deba@482
   321
        "The upper bound for the first row should be 1.");
deba@481
   322
  e = clp->row(upright);
deba@482
   323
  check(e[x1] == 1, "The first coefficient should 1.");
deba@482
   324
  check(e[x2] == 1, "The second coefficient should 1.");
deba@481
   325
deba@481
   326
  de = clp->col(x1);
deba@482
   327
  check(de[upright] == 1, "The first coefficient should 1.");
deba@481
   328
deba@481
   329
  delete clp;
deba@481
   330
deba@481
   331
  //Maximization of x1+x2
deba@481
   332
  //over the triangle with vertices (0,0) (0,1) (1,0)
deba@481
   333
  double expected_opt=1;
deba@482
   334
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   335
deba@481
   336
  //Minimization
deba@482
   337
  lp.sense(lp.MIN);
deba@481
   338
  expected_opt=0;
deba@482
   339
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   340
deba@481
   341
  //Vertex (-1,0) instead of (0,0)
deba@482
   342
  lp.colLowerBound(x1, -LpSolver::INF);
deba@481
   343
  expected_opt=-1;
deba@482
   344
  solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt);
deba@481
   345
deba@481
   346
  //Erase one constraint and return to maximization
deba@482
   347
  lp.erase(upright);
deba@482
   348
  lp.sense(lp.MAX);
deba@482
   349
  expected_opt=LpSolver::INF;
deba@482
   350
  solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt);
deba@481
   351
deba@481
   352
  //Infeasibilty
deba@481
   353
  lp.addRow(x1+x2 <=-2);
deba@482
   354
  solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt);
deba@481
   355
deba@481
   356
}
deba@481
   357
deba@481
   358
int main()
deba@481
   359
{
deba@481
   360
  LpSkeleton lp_skel;
deba@481
   361
  lpTest(lp_skel);
deba@481
   362
deba@481
   363
#ifdef HAVE_GLPK
deba@482
   364
  {
alpar@485
   365
    GlpkLp lp_glpk1,lp_glpk2;
deba@482
   366
    lpTest(lp_glpk1);
deba@482
   367
    aTest(lp_glpk2);
deba@482
   368
  }
deba@481
   369
#endif
deba@481
   370
deba@481
   371
#ifdef HAVE_CPLEX
deba@482
   372
  try {
alpar@485
   373
    CplexLp lp_cplex1,lp_cplex2;
deba@482
   374
    lpTest(lp_cplex1);
deba@482
   375
    aTest(lp_cplex2);
deba@482
   376
  } catch (CplexEnv::LicenseError& error) {
deba@482
   377
#ifdef LEMON_FORCE_CPLEX_CHECK
deba@482
   378
    check(false, error.what());
deba@482
   379
#else
deba@482
   380
    std::cerr << error.what() << std::endl;
deba@482
   381
    std::cerr << "Cplex license check failed, lp check skipped" << std::endl;
deba@482
   382
#endif
deba@482
   383
  }
deba@481
   384
#endif
deba@481
   385
deba@481
   386
#ifdef HAVE_SOPLEX
deba@482
   387
  {
alpar@485
   388
    SoplexLp lp_soplex1,lp_soplex2;
deba@482
   389
    lpTest(lp_soplex1);
deba@482
   390
    aTest(lp_soplex2);
deba@482
   391
  }
deba@482
   392
#endif
deba@482
   393
deba@482
   394
#ifdef HAVE_CLP
deba@482
   395
  {
alpar@485
   396
    ClpLp lp_clp1,lp_clp2;
deba@482
   397
    lpTest(lp_clp1);
deba@482
   398
    aTest(lp_clp2);
deba@482
   399
  }
deba@481
   400
#endif
deba@481
   401
deba@481
   402
  return 0;
deba@481
   403
}