src/glpapi09.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glpapi09.c (mixed integer programming routines) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpios.h"
alpar@1
    26
#include "glpnpp.h"
alpar@1
    27
alpar@1
    28
/***********************************************************************
alpar@1
    29
*  NAME
alpar@1
    30
*
alpar@1
    31
*  glp_set_col_kind - set (change) column kind
alpar@1
    32
*
alpar@1
    33
*  SYNOPSIS
alpar@1
    34
*
alpar@1
    35
*  void glp_set_col_kind(glp_prob *mip, int j, int kind);
alpar@1
    36
*
alpar@1
    37
*  DESCRIPTION
alpar@1
    38
*
alpar@1
    39
*  The routine glp_set_col_kind sets (changes) the kind of j-th column
alpar@1
    40
*  (structural variable) as specified by the parameter kind:
alpar@1
    41
*
alpar@1
    42
*  GLP_CV - continuous variable;
alpar@1
    43
*  GLP_IV - integer variable;
alpar@1
    44
*  GLP_BV - binary variable. */
alpar@1
    45
alpar@1
    46
void glp_set_col_kind(glp_prob *mip, int j, int kind)
alpar@1
    47
{     GLPCOL *col;
alpar@1
    48
      if (!(1 <= j && j <= mip->n))
alpar@1
    49
         xerror("glp_set_col_kind: j = %d; column number out of range\n"
alpar@1
    50
            , j);
alpar@1
    51
      col = mip->col[j];
alpar@1
    52
      switch (kind)
alpar@1
    53
      {  case GLP_CV:
alpar@1
    54
            col->kind = GLP_CV;
alpar@1
    55
            break;
alpar@1
    56
         case GLP_IV:
alpar@1
    57
            col->kind = GLP_IV;
alpar@1
    58
            break;
alpar@1
    59
         case GLP_BV:
alpar@1
    60
            col->kind = GLP_IV;
alpar@1
    61
            if (!(col->type == GLP_DB && col->lb == 0.0 && col->ub ==
alpar@1
    62
               1.0)) glp_set_col_bnds(mip, j, GLP_DB, 0.0, 1.0);
alpar@1
    63
            break;
alpar@1
    64
         default:
alpar@1
    65
            xerror("glp_set_col_kind: j = %d; kind = %d; invalid column"
alpar@1
    66
               " kind\n", j, kind);
alpar@1
    67
      }
alpar@1
    68
      return;
alpar@1
    69
}
alpar@1
    70
alpar@1
    71
/***********************************************************************
alpar@1
    72
*  NAME
alpar@1
    73
*
alpar@1
    74
*  glp_get_col_kind - retrieve column kind
alpar@1
    75
*
alpar@1
    76
*  SYNOPSIS
alpar@1
    77
*
alpar@1
    78
*  int glp_get_col_kind(glp_prob *mip, int j);
alpar@1
    79
*
alpar@1
    80
*  RETURNS
alpar@1
    81
*
alpar@1
    82
*  The routine glp_get_col_kind returns the kind of j-th column, i.e.
alpar@1
    83
*  the kind of corresponding structural variable, as follows:
alpar@1
    84
*
alpar@1
    85
*  GLP_CV - continuous variable;
alpar@1
    86
*  GLP_IV - integer variable;
alpar@1
    87
*  GLP_BV - binary variable */
alpar@1
    88
alpar@1
    89
int glp_get_col_kind(glp_prob *mip, int j)
alpar@1
    90
{     GLPCOL *col;
alpar@1
    91
      int kind;
alpar@1
    92
      if (!(1 <= j && j <= mip->n))
alpar@1
    93
         xerror("glp_get_col_kind: j = %d; column number out of range\n"
alpar@1
    94
            , j);
alpar@1
    95
      col = mip->col[j];
alpar@1
    96
      kind = col->kind;
alpar@1
    97
      switch (kind)
alpar@1
    98
      {  case GLP_CV:
alpar@1
    99
            break;
alpar@1
   100
         case GLP_IV:
alpar@1
   101
            if (col->type == GLP_DB && col->lb == 0.0 && col->ub == 1.0)
alpar@1
   102
               kind = GLP_BV;
alpar@1
   103
            break;
alpar@1
   104
         default:
alpar@1
   105
            xassert(kind != kind);
alpar@1
   106
      }
alpar@1
   107
      return kind;
alpar@1
   108
}
alpar@1
   109
alpar@1
   110
/***********************************************************************
alpar@1
   111
*  NAME
alpar@1
   112
*
alpar@1
   113
*  glp_get_num_int - retrieve number of integer columns
alpar@1
   114
*
alpar@1
   115
*  SYNOPSIS
alpar@1
   116
*
alpar@1
   117
*  int glp_get_num_int(glp_prob *mip);
alpar@1
   118
*
alpar@1
   119
*  RETURNS
alpar@1
   120
*
alpar@1
   121
*  The routine glp_get_num_int returns the current number of columns,
alpar@1
   122
*  which are marked as integer. */
alpar@1
   123
alpar@1
   124
int glp_get_num_int(glp_prob *mip)
alpar@1
   125
{     GLPCOL *col;
alpar@1
   126
      int j, count = 0;
alpar@1
   127
      for (j = 1; j <= mip->n; j++)
alpar@1
   128
      {  col = mip->col[j];
alpar@1
   129
         if (col->kind == GLP_IV) count++;
alpar@1
   130
      }
alpar@1
   131
      return count;
alpar@1
   132
}
alpar@1
   133
alpar@1
   134
/***********************************************************************
alpar@1
   135
*  NAME
alpar@1
   136
*
alpar@1
   137
*  glp_get_num_bin - retrieve number of binary columns
alpar@1
   138
*
alpar@1
   139
*  SYNOPSIS
alpar@1
   140
*
alpar@1
   141
*  int glp_get_num_bin(glp_prob *mip);
alpar@1
   142
*
alpar@1
   143
*  RETURNS
alpar@1
   144
*
alpar@1
   145
*  The routine glp_get_num_bin returns the current number of columns,
alpar@1
   146
*  which are marked as binary. */
alpar@1
   147
alpar@1
   148
int glp_get_num_bin(glp_prob *mip)
alpar@1
   149
{     GLPCOL *col;
alpar@1
   150
      int j, count = 0;
alpar@1
   151
      for (j = 1; j <= mip->n; j++)
alpar@1
   152
      {  col = mip->col[j];
alpar@1
   153
         if (col->kind == GLP_IV && col->type == GLP_DB && col->lb ==
alpar@1
   154
            0.0 && col->ub == 1.0) count++;
alpar@1
   155
      }
alpar@1
   156
      return count;
alpar@1
   157
}
alpar@1
   158
alpar@1
   159
/***********************************************************************
alpar@1
   160
*  NAME
alpar@1
   161
*
alpar@1
   162
*  glp_intopt - solve MIP problem with the branch-and-bound method
alpar@1
   163
*
alpar@1
   164
*  SYNOPSIS
alpar@1
   165
*
alpar@1
   166
*  int glp_intopt(glp_prob *P, const glp_iocp *parm);
alpar@1
   167
*
alpar@1
   168
*  DESCRIPTION
alpar@1
   169
*
alpar@1
   170
*  The routine glp_intopt is a driver to the MIP solver based on the
alpar@1
   171
*  branch-and-bound method.
alpar@1
   172
*
alpar@1
   173
*  On entry the problem object should contain optimal solution to LP
alpar@1
   174
*  relaxation (which can be obtained with the routine glp_simplex).
alpar@1
   175
*
alpar@1
   176
*  The MIP solver has a set of control parameters. Values of the control
alpar@1
   177
*  parameters can be passed in a structure glp_iocp, which the parameter
alpar@1
   178
*  parm points to.
alpar@1
   179
*
alpar@1
   180
*  The parameter parm can be specified as NULL, in which case the MIP
alpar@1
   181
*  solver uses default settings.
alpar@1
   182
*
alpar@1
   183
*  RETURNS
alpar@1
   184
*
alpar@1
   185
*  0  The MIP problem instance has been successfully solved. This code
alpar@1
   186
*     does not necessarily mean that the solver has found optimal
alpar@1
   187
*     solution. It only means that the solution process was successful.
alpar@1
   188
*
alpar@1
   189
*  GLP_EBOUND
alpar@1
   190
*     Unable to start the search, because some double-bounded variables
alpar@1
   191
*     have incorrect bounds or some integer variables have non-integer
alpar@1
   192
*     (fractional) bounds.
alpar@1
   193
*
alpar@1
   194
*  GLP_EROOT
alpar@1
   195
*     Unable to start the search, because optimal basis for initial LP
alpar@1
   196
*     relaxation is not provided.
alpar@1
   197
*
alpar@1
   198
*  GLP_EFAIL
alpar@1
   199
*     The search was prematurely terminated due to the solver failure.
alpar@1
   200
*
alpar@1
   201
*  GLP_EMIPGAP
alpar@1
   202
*     The search was prematurely terminated, because the relative mip
alpar@1
   203
*     gap tolerance has been reached.
alpar@1
   204
*
alpar@1
   205
*  GLP_ETMLIM
alpar@1
   206
*     The search was prematurely terminated, because the time limit has
alpar@1
   207
*     been exceeded.
alpar@1
   208
*
alpar@1
   209
*  GLP_ENOPFS
alpar@1
   210
*     The MIP problem instance has no primal feasible solution (only if
alpar@1
   211
*     the MIP presolver is used).
alpar@1
   212
*
alpar@1
   213
*  GLP_ENODFS
alpar@1
   214
*     LP relaxation of the MIP problem instance has no dual feasible
alpar@1
   215
*     solution (only if the MIP presolver is used).
alpar@1
   216
*
alpar@1
   217
*  GLP_ESTOP
alpar@1
   218
*     The search was prematurely terminated by application. */
alpar@1
   219
alpar@1
   220
static int solve_mip(glp_prob *P, const glp_iocp *parm)
alpar@1
   221
{     /* solve MIP directly without using the preprocessor */
alpar@1
   222
      glp_tree *T;
alpar@1
   223
      int ret;
alpar@1
   224
      /* optimal basis to LP relaxation must be provided */
alpar@1
   225
      if (glp_get_status(P) != GLP_OPT)
alpar@1
   226
      {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   227
            xprintf("glp_intopt: optimal basis to initial LP relaxation"
alpar@1
   228
               " not provided\n");
alpar@1
   229
         ret = GLP_EROOT;
alpar@1
   230
         goto done;
alpar@1
   231
      }
alpar@1
   232
      /* it seems all is ok */
alpar@1
   233
      if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   234
         xprintf("Integer optimization begins...\n");
alpar@1
   235
      /* create the branch-and-bound tree */
alpar@1
   236
      T = ios_create_tree(P, parm);
alpar@1
   237
      /* solve the problem instance */
alpar@1
   238
      ret = ios_driver(T);
alpar@1
   239
      /* delete the branch-and-bound tree */
alpar@1
   240
      ios_delete_tree(T);
alpar@1
   241
      /* analyze exit code reported by the mip driver */
alpar@1
   242
      if (ret == 0)
alpar@1
   243
      {  if (P->mip_stat == GLP_FEAS)
alpar@1
   244
         {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   245
               xprintf("INTEGER OPTIMAL SOLUTION FOUND\n");
alpar@1
   246
            P->mip_stat = GLP_OPT;
alpar@1
   247
         }
alpar@1
   248
         else
alpar@1
   249
         {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   250
               xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n");
alpar@1
   251
            P->mip_stat = GLP_NOFEAS;
alpar@1
   252
         }
alpar@1
   253
      }
alpar@1
   254
      else if (ret == GLP_EMIPGAP)
alpar@1
   255
      {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   256
            xprintf("RELATIVE MIP GAP TOLERANCE REACHED; SEARCH TERMINA"
alpar@1
   257
               "TED\n");
alpar@1
   258
      }
alpar@1
   259
      else if (ret == GLP_ETMLIM)
alpar@1
   260
      {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   261
            xprintf("TIME LIMIT EXCEEDED; SEARCH TERMINATED\n");
alpar@1
   262
      }
alpar@1
   263
      else if (ret == GLP_EFAIL)
alpar@1
   264
      {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   265
            xprintf("glp_intopt: cannot solve current LP relaxation\n");
alpar@1
   266
      }
alpar@1
   267
      else if (ret == GLP_ESTOP)
alpar@1
   268
      {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   269
            xprintf("SEARCH TERMINATED BY APPLICATION\n");
alpar@1
   270
      }
alpar@1
   271
      else
alpar@1
   272
         xassert(ret != ret);
alpar@1
   273
done: return ret;
alpar@1
   274
}
alpar@1
   275
alpar@1
   276
static int preprocess_and_solve_mip(glp_prob *P, const glp_iocp *parm)
alpar@1
   277
{     /* solve MIP using the preprocessor */
alpar@1
   278
      ENV *env = get_env_ptr();
alpar@1
   279
      int term_out = env->term_out;
alpar@1
   280
      NPP *npp;
alpar@1
   281
      glp_prob *mip = NULL;
alpar@1
   282
      glp_bfcp bfcp;
alpar@1
   283
      glp_smcp smcp;
alpar@1
   284
      int ret;
alpar@1
   285
      if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   286
         xprintf("Preprocessing...\n");
alpar@1
   287
      /* create preprocessor workspace */
alpar@1
   288
      npp = npp_create_wksp();
alpar@1
   289
      /* load original problem into the preprocessor workspace */
alpar@1
   290
      npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF);
alpar@1
   291
      /* process MIP prior to applying the branch-and-bound method */
alpar@1
   292
      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
alpar@1
   293
         env->term_out = GLP_OFF;
alpar@1
   294
      else
alpar@1
   295
         env->term_out = GLP_ON;
alpar@1
   296
      ret = npp_integer(npp, parm);
alpar@1
   297
      env->term_out = term_out;
alpar@1
   298
      if (ret == 0)
alpar@1
   299
         ;
alpar@1
   300
      else if (ret == GLP_ENOPFS)
alpar@1
   301
      {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   302
            xprintf("PROBLEM HAS NO PRIMAL FEASIBLE SOLUTION\n");
alpar@1
   303
      }
alpar@1
   304
      else if (ret == GLP_ENODFS)
alpar@1
   305
      {  if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   306
            xprintf("LP RELAXATION HAS NO DUAL FEASIBLE SOLUTION\n");
alpar@1
   307
      }
alpar@1
   308
      else
alpar@1
   309
         xassert(ret != ret);
alpar@1
   310
      if (ret != 0) goto done;
alpar@1
   311
      /* build transformed MIP */
alpar@1
   312
      mip = glp_create_prob();
alpar@1
   313
      npp_build_prob(npp, mip);
alpar@1
   314
      /* if the transformed MIP is empty, it has empty solution, which
alpar@1
   315
         is optimal */
alpar@1
   316
      if (mip->m == 0 && mip->n == 0)
alpar@1
   317
      {  mip->mip_stat = GLP_OPT;
alpar@1
   318
         mip->mip_obj = mip->c0;
alpar@1
   319
         if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   320
         {  xprintf("Objective value = %17.9e\n", mip->mip_obj);
alpar@1
   321
            xprintf("INTEGER OPTIMAL SOLUTION FOUND BY MIP PREPROCESSOR"
alpar@1
   322
               "\n");
alpar@1
   323
         }
alpar@1
   324
         goto post;
alpar@1
   325
      }
alpar@1
   326
      /* display some statistics */
alpar@1
   327
      if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   328
      {  int ni = glp_get_num_int(mip);
alpar@1
   329
         int nb = glp_get_num_bin(mip);
alpar@1
   330
         char s[50];
alpar@1
   331
         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
alpar@1
   332
            mip->m, mip->m == 1 ? "" : "s", mip->n, mip->n == 1 ? "" :
alpar@1
   333
            "s", mip->nnz, mip->nnz == 1 ? "" : "s");
alpar@1
   334
         if (nb == 0)
alpar@1
   335
            strcpy(s, "none of");
alpar@1
   336
         else if (ni == 1 && nb == 1)
alpar@1
   337
            strcpy(s, "");
alpar@1
   338
         else if (nb == 1)
alpar@1
   339
            strcpy(s, "one of");
alpar@1
   340
         else if (nb == ni)
alpar@1
   341
            strcpy(s, "all of");
alpar@1
   342
         else
alpar@1
   343
            sprintf(s, "%d of", nb);
alpar@1
   344
         xprintf("%d integer variable%s, %s which %s binary\n",
alpar@1
   345
            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
alpar@1
   346
      }
alpar@1
   347
      /* inherit basis factorization control parameters */
alpar@1
   348
      glp_get_bfcp(P, &bfcp);
alpar@1
   349
      glp_set_bfcp(mip, &bfcp);
alpar@1
   350
      /* scale the transformed problem */
alpar@1
   351
      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
alpar@1
   352
         env->term_out = GLP_OFF;
alpar@1
   353
      else
alpar@1
   354
         env->term_out = GLP_ON;
alpar@1
   355
      glp_scale_prob(mip,
alpar@1
   356
         GLP_SF_GM | GLP_SF_EQ | GLP_SF_2N | GLP_SF_SKIP);
alpar@1
   357
      env->term_out = term_out;
alpar@1
   358
      /* build advanced initial basis */
alpar@1
   359
      if (!term_out || parm->msg_lev < GLP_MSG_ALL)
alpar@1
   360
         env->term_out = GLP_OFF;
alpar@1
   361
      else
alpar@1
   362
         env->term_out = GLP_ON;
alpar@1
   363
      glp_adv_basis(mip, 0);
alpar@1
   364
      env->term_out = term_out;
alpar@1
   365
      /* solve initial LP relaxation */
alpar@1
   366
      if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   367
         xprintf("Solving LP relaxation...\n");
alpar@1
   368
      glp_init_smcp(&smcp);
alpar@1
   369
      smcp.msg_lev = parm->msg_lev;
alpar@1
   370
      mip->it_cnt = P->it_cnt;
alpar@1
   371
      ret = glp_simplex(mip, &smcp);
alpar@1
   372
      P->it_cnt = mip->it_cnt;
alpar@1
   373
      if (ret != 0)
alpar@1
   374
      {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   375
            xprintf("glp_intopt: cannot solve LP relaxation\n");
alpar@1
   376
         ret = GLP_EFAIL;
alpar@1
   377
         goto done;
alpar@1
   378
      }
alpar@1
   379
      /* check status of the basic solution */
alpar@1
   380
      ret = glp_get_status(mip);
alpar@1
   381
      if (ret == GLP_OPT)
alpar@1
   382
         ret = 0;
alpar@1
   383
      else if (ret == GLP_NOFEAS)
alpar@1
   384
         ret = GLP_ENOPFS;
alpar@1
   385
      else if (ret == GLP_UNBND)
alpar@1
   386
         ret = GLP_ENODFS;
alpar@1
   387
      else
alpar@1
   388
         xassert(ret != ret);
alpar@1
   389
      if (ret != 0) goto done;
alpar@1
   390
      /* solve the transformed MIP */
alpar@1
   391
      mip->it_cnt = P->it_cnt;
alpar@1
   392
      ret = solve_mip(mip, parm);
alpar@1
   393
      P->it_cnt = mip->it_cnt;
alpar@1
   394
      /* only integer feasible solution can be postprocessed */
alpar@1
   395
      if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS))
alpar@1
   396
      {  P->mip_stat = mip->mip_stat;
alpar@1
   397
         goto done;
alpar@1
   398
      }
alpar@1
   399
      /* postprocess solution from the transformed MIP */
alpar@1
   400
post: npp_postprocess(npp, mip);
alpar@1
   401
      /* the transformed MIP is no longer needed */
alpar@1
   402
      glp_delete_prob(mip), mip = NULL;
alpar@1
   403
      /* store solution to the original problem */
alpar@1
   404
      npp_unload_sol(npp, P);
alpar@1
   405
done: /* delete the transformed MIP, if it exists */
alpar@1
   406
      if (mip != NULL) glp_delete_prob(mip);
alpar@1
   407
      /* delete preprocessor workspace */
alpar@1
   408
      npp_delete_wksp(npp);
alpar@1
   409
      return ret;
alpar@1
   410
}
alpar@1
   411
alpar@1
   412
#ifndef HAVE_ALIEN_SOLVER /* 28/V-2010 */
alpar@1
   413
int _glp_intopt1(glp_prob *P, const glp_iocp *parm)
alpar@1
   414
{     xassert(P == P);
alpar@1
   415
      xassert(parm == parm);
alpar@1
   416
      xprintf("glp_intopt: no alien solver is available\n");
alpar@1
   417
      return GLP_EFAIL;
alpar@1
   418
}
alpar@1
   419
#endif
alpar@1
   420
alpar@1
   421
int glp_intopt(glp_prob *P, const glp_iocp *parm)
alpar@1
   422
{     /* solve MIP problem with the branch-and-bound method */
alpar@1
   423
      glp_iocp _parm;
alpar@1
   424
      int i, j, ret;
alpar@1
   425
      /* check problem object */
alpar@1
   426
      if (P == NULL || P->magic != GLP_PROB_MAGIC)
alpar@1
   427
         xerror("glp_intopt: P = %p; invalid problem object\n", P);
alpar@1
   428
      if (P->tree != NULL)
alpar@1
   429
         xerror("glp_intopt: operation not allowed\n");
alpar@1
   430
      /* check control parameters */
alpar@1
   431
      if (parm == NULL)
alpar@1
   432
         parm = &_parm, glp_init_iocp((glp_iocp *)parm);
alpar@1
   433
      if (!(parm->msg_lev == GLP_MSG_OFF ||
alpar@1
   434
            parm->msg_lev == GLP_MSG_ERR ||
alpar@1
   435
            parm->msg_lev == GLP_MSG_ON  ||
alpar@1
   436
            parm->msg_lev == GLP_MSG_ALL ||
alpar@1
   437
            parm->msg_lev == GLP_MSG_DBG))
alpar@1
   438
         xerror("glp_intopt: msg_lev = %d; invalid parameter\n",
alpar@1
   439
            parm->msg_lev);
alpar@1
   440
      if (!(parm->br_tech == GLP_BR_FFV ||
alpar@1
   441
            parm->br_tech == GLP_BR_LFV ||
alpar@1
   442
            parm->br_tech == GLP_BR_MFV ||
alpar@1
   443
            parm->br_tech == GLP_BR_DTH ||
alpar@1
   444
            parm->br_tech == GLP_BR_PCH))
alpar@1
   445
         xerror("glp_intopt: br_tech = %d; invalid parameter\n",
alpar@1
   446
            parm->br_tech);
alpar@1
   447
      if (!(parm->bt_tech == GLP_BT_DFS ||
alpar@1
   448
            parm->bt_tech == GLP_BT_BFS ||
alpar@1
   449
            parm->bt_tech == GLP_BT_BLB ||
alpar@1
   450
            parm->bt_tech == GLP_BT_BPH))
alpar@1
   451
         xerror("glp_intopt: bt_tech = %d; invalid parameter\n",
alpar@1
   452
            parm->bt_tech);
alpar@1
   453
      if (!(0.0 < parm->tol_int && parm->tol_int < 1.0))
alpar@1
   454
         xerror("glp_intopt: tol_int = %g; invalid parameter\n",
alpar@1
   455
            parm->tol_int);
alpar@1
   456
      if (!(0.0 < parm->tol_obj && parm->tol_obj < 1.0))
alpar@1
   457
         xerror("glp_intopt: tol_obj = %g; invalid parameter\n",
alpar@1
   458
            parm->tol_obj);
alpar@1
   459
      if (parm->tm_lim < 0)
alpar@1
   460
         xerror("glp_intopt: tm_lim = %d; invalid parameter\n",
alpar@1
   461
            parm->tm_lim);
alpar@1
   462
      if (parm->out_frq < 0)
alpar@1
   463
         xerror("glp_intopt: out_frq = %d; invalid parameter\n",
alpar@1
   464
            parm->out_frq);
alpar@1
   465
      if (parm->out_dly < 0)
alpar@1
   466
         xerror("glp_intopt: out_dly = %d; invalid parameter\n",
alpar@1
   467
            parm->out_dly);
alpar@1
   468
      if (!(0 <= parm->cb_size && parm->cb_size <= 256))
alpar@1
   469
         xerror("glp_intopt: cb_size = %d; invalid parameter\n",
alpar@1
   470
            parm->cb_size);
alpar@1
   471
      if (!(parm->pp_tech == GLP_PP_NONE ||
alpar@1
   472
            parm->pp_tech == GLP_PP_ROOT ||
alpar@1
   473
            parm->pp_tech == GLP_PP_ALL))
alpar@1
   474
         xerror("glp_intopt: pp_tech = %d; invalid parameter\n",
alpar@1
   475
            parm->pp_tech);
alpar@1
   476
      if (parm->mip_gap < 0.0)
alpar@1
   477
         xerror("glp_intopt: mip_gap = %g; invalid parameter\n",
alpar@1
   478
            parm->mip_gap);
alpar@1
   479
      if (!(parm->mir_cuts == GLP_ON || parm->mir_cuts == GLP_OFF))
alpar@1
   480
         xerror("glp_intopt: mir_cuts = %d; invalid parameter\n",
alpar@1
   481
            parm->mir_cuts);
alpar@1
   482
      if (!(parm->gmi_cuts == GLP_ON || parm->gmi_cuts == GLP_OFF))
alpar@1
   483
         xerror("glp_intopt: gmi_cuts = %d; invalid parameter\n",
alpar@1
   484
            parm->gmi_cuts);
alpar@1
   485
      if (!(parm->cov_cuts == GLP_ON || parm->cov_cuts == GLP_OFF))
alpar@1
   486
         xerror("glp_intopt: cov_cuts = %d; invalid parameter\n",
alpar@1
   487
            parm->cov_cuts);
alpar@1
   488
      if (!(parm->clq_cuts == GLP_ON || parm->clq_cuts == GLP_OFF))
alpar@1
   489
         xerror("glp_intopt: clq_cuts = %d; invalid parameter\n",
alpar@1
   490
            parm->clq_cuts);
alpar@1
   491
      if (!(parm->presolve == GLP_ON || parm->presolve == GLP_OFF))
alpar@1
   492
         xerror("glp_intopt: presolve = %d; invalid parameter\n",
alpar@1
   493
            parm->presolve);
alpar@1
   494
      if (!(parm->binarize == GLP_ON || parm->binarize == GLP_OFF))
alpar@1
   495
         xerror("glp_intopt: binarize = %d; invalid parameter\n",
alpar@1
   496
            parm->binarize);
alpar@1
   497
      if (!(parm->fp_heur == GLP_ON || parm->fp_heur == GLP_OFF))
alpar@1
   498
         xerror("glp_intopt: fp_heur = %d; invalid parameter\n",
alpar@1
   499
            parm->fp_heur);
alpar@1
   500
#if 1 /* 28/V-2010 */
alpar@1
   501
      if (!(parm->alien == GLP_ON || parm->alien == GLP_OFF))
alpar@1
   502
         xerror("glp_intopt: alien = %d; invalid parameter\n",
alpar@1
   503
            parm->alien);
alpar@1
   504
#endif
alpar@1
   505
      /* integer solution is currently undefined */
alpar@1
   506
      P->mip_stat = GLP_UNDEF;
alpar@1
   507
      P->mip_obj = 0.0;
alpar@1
   508
      /* check bounds of double-bounded variables */
alpar@1
   509
      for (i = 1; i <= P->m; i++)
alpar@1
   510
      {  GLPROW *row = P->row[i];
alpar@1
   511
         if (row->type == GLP_DB && row->lb >= row->ub)
alpar@1
   512
         {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   513
               xprintf("glp_intopt: row %d: lb = %g, ub = %g; incorrect"
alpar@1
   514
                  " bounds\n", i, row->lb, row->ub);
alpar@1
   515
            ret = GLP_EBOUND;
alpar@1
   516
            goto done;
alpar@1
   517
         }
alpar@1
   518
      }
alpar@1
   519
      for (j = 1; j <= P->n; j++)
alpar@1
   520
      {  GLPCOL *col = P->col[j];
alpar@1
   521
         if (col->type == GLP_DB && col->lb >= col->ub)
alpar@1
   522
         {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   523
               xprintf("glp_intopt: column %d: lb = %g, ub = %g; incorr"
alpar@1
   524
                  "ect bounds\n", j, col->lb, col->ub);
alpar@1
   525
            ret = GLP_EBOUND;
alpar@1
   526
            goto done;
alpar@1
   527
         }
alpar@1
   528
      }
alpar@1
   529
      /* bounds of all integer variables must be integral */
alpar@1
   530
      for (j = 1; j <= P->n; j++)
alpar@1
   531
      {  GLPCOL *col = P->col[j];
alpar@1
   532
         if (col->kind != GLP_IV) continue;
alpar@1
   533
         if (col->type == GLP_LO || col->type == GLP_DB)
alpar@1
   534
         {  if (col->lb != floor(col->lb))
alpar@1
   535
            {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   536
                  xprintf("glp_intopt: integer column %d has non-intege"
alpar@1
   537
                     "r lower bound %g\n", j, col->lb);
alpar@1
   538
               ret = GLP_EBOUND;
alpar@1
   539
               goto done;
alpar@1
   540
            }
alpar@1
   541
         }
alpar@1
   542
         if (col->type == GLP_UP || col->type == GLP_DB)
alpar@1
   543
         {  if (col->ub != floor(col->ub))
alpar@1
   544
            {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   545
                  xprintf("glp_intopt: integer column %d has non-intege"
alpar@1
   546
                     "r upper bound %g\n", j, col->ub);
alpar@1
   547
               ret = GLP_EBOUND;
alpar@1
   548
               goto done;
alpar@1
   549
            }
alpar@1
   550
         }
alpar@1
   551
         if (col->type == GLP_FX)
alpar@1
   552
         {  if (col->lb != floor(col->lb))
alpar@1
   553
            {  if (parm->msg_lev >= GLP_MSG_ERR)
alpar@1
   554
                  xprintf("glp_intopt: integer column %d has non-intege"
alpar@1
   555
                     "r fixed value %g\n", j, col->lb);
alpar@1
   556
               ret = GLP_EBOUND;
alpar@1
   557
               goto done;
alpar@1
   558
            }
alpar@1
   559
         }
alpar@1
   560
      }
alpar@1
   561
      /* solve MIP problem */
alpar@1
   562
      if (parm->msg_lev >= GLP_MSG_ALL)
alpar@1
   563
      {  int ni = glp_get_num_int(P);
alpar@1
   564
         int nb = glp_get_num_bin(P);
alpar@1
   565
         char s[50];
alpar@1
   566
         xprintf("GLPK Integer Optimizer, v%s\n", glp_version());
alpar@1
   567
         xprintf("%d row%s, %d column%s, %d non-zero%s\n",
alpar@1
   568
            P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
alpar@1
   569
            P->nnz, P->nnz == 1 ? "" : "s");
alpar@1
   570
         if (nb == 0)
alpar@1
   571
            strcpy(s, "none of");
alpar@1
   572
         else if (ni == 1 && nb == 1)
alpar@1
   573
            strcpy(s, "");
alpar@1
   574
         else if (nb == 1)
alpar@1
   575
            strcpy(s, "one of");
alpar@1
   576
         else if (nb == ni)
alpar@1
   577
            strcpy(s, "all of");
alpar@1
   578
         else
alpar@1
   579
            sprintf(s, "%d of", nb);
alpar@1
   580
         xprintf("%d integer variable%s, %s which %s binary\n",
alpar@1
   581
            ni, ni == 1 ? "" : "s", s, nb == 1 ? "is" : "are");
alpar@1
   582
      }
alpar@1
   583
#if 1 /* 28/V-2010 */
alpar@1
   584
      if (parm->alien)
alpar@1
   585
      {  /* use alien integer optimizer */
alpar@1
   586
         ret = _glp_intopt1(P, parm);
alpar@1
   587
         goto done;
alpar@1
   588
      }
alpar@1
   589
#endif
alpar@1
   590
      if (!parm->presolve)
alpar@1
   591
         ret = solve_mip(P, parm);
alpar@1
   592
      else
alpar@1
   593
         ret = preprocess_and_solve_mip(P, parm);
alpar@1
   594
done: /* return to the application program */
alpar@1
   595
      return ret;
alpar@1
   596
}
alpar@1
   597
alpar@1
   598
/***********************************************************************
alpar@1
   599
*  NAME
alpar@1
   600
*
alpar@1
   601
*  glp_init_iocp - initialize integer optimizer control parameters
alpar@1
   602
*
alpar@1
   603
*  SYNOPSIS
alpar@1
   604
*
alpar@1
   605
*  void glp_init_iocp(glp_iocp *parm);
alpar@1
   606
*
alpar@1
   607
*  DESCRIPTION
alpar@1
   608
*
alpar@1
   609
*  The routine glp_init_iocp initializes control parameters, which are
alpar@1
   610
*  used by the integer optimizer, with default values.
alpar@1
   611
*
alpar@1
   612
*  Default values of the control parameters are stored in a glp_iocp
alpar@1
   613
*  structure, which the parameter parm points to. */
alpar@1
   614
alpar@1
   615
void glp_init_iocp(glp_iocp *parm)
alpar@1
   616
{     parm->msg_lev = GLP_MSG_ALL;
alpar@1
   617
      parm->br_tech = GLP_BR_DTH;
alpar@1
   618
      parm->bt_tech = GLP_BT_BLB;
alpar@1
   619
      parm->tol_int = 1e-5;
alpar@1
   620
      parm->tol_obj = 1e-7;
alpar@1
   621
      parm->tm_lim = INT_MAX;
alpar@1
   622
      parm->out_frq = 5000;
alpar@1
   623
      parm->out_dly = 10000;
alpar@1
   624
      parm->cb_func = NULL;
alpar@1
   625
      parm->cb_info = NULL;
alpar@1
   626
      parm->cb_size = 0;
alpar@1
   627
      parm->pp_tech = GLP_PP_ALL;
alpar@1
   628
      parm->mip_gap = 0.0;
alpar@1
   629
      parm->mir_cuts = GLP_OFF;
alpar@1
   630
      parm->gmi_cuts = GLP_OFF;
alpar@1
   631
      parm->cov_cuts = GLP_OFF;
alpar@1
   632
      parm->clq_cuts = GLP_OFF;
alpar@1
   633
      parm->presolve = GLP_OFF;
alpar@1
   634
      parm->binarize = GLP_OFF;
alpar@1
   635
      parm->fp_heur = GLP_OFF;
alpar@1
   636
#if 1 /* 28/V-2010 */
alpar@1
   637
      parm->alien = GLP_OFF;
alpar@1
   638
#endif
alpar@1
   639
      return;
alpar@1
   640
}
alpar@1
   641
alpar@1
   642
/***********************************************************************
alpar@1
   643
*  NAME
alpar@1
   644
*
alpar@1
   645
*  glp_mip_status - retrieve status of MIP solution
alpar@1
   646
*
alpar@1
   647
*  SYNOPSIS
alpar@1
   648
*
alpar@1
   649
*  int glp_mip_status(glp_prob *mip);
alpar@1
   650
*
alpar@1
   651
*  RETURNS
alpar@1
   652
*
alpar@1
   653
*  The routine lpx_mip_status reports the status of MIP solution found
alpar@1
   654
*  by the branch-and-bound solver as follows:
alpar@1
   655
*
alpar@1
   656
*  GLP_UNDEF  - MIP solution is undefined;
alpar@1
   657
*  GLP_OPT    - MIP solution is integer optimal;
alpar@1
   658
*  GLP_FEAS   - MIP solution is integer feasible but its optimality
alpar@1
   659
*               (or non-optimality) has not been proven, perhaps due to
alpar@1
   660
*               premature termination of the search;
alpar@1
   661
*  GLP_NOFEAS - problem has no integer feasible solution (proven by the
alpar@1
   662
*               solver). */
alpar@1
   663
alpar@1
   664
int glp_mip_status(glp_prob *mip)
alpar@1
   665
{     int mip_stat = mip->mip_stat;
alpar@1
   666
      return mip_stat;
alpar@1
   667
}
alpar@1
   668
alpar@1
   669
/***********************************************************************
alpar@1
   670
*  NAME
alpar@1
   671
*
alpar@1
   672
*  glp_mip_obj_val - retrieve objective value (MIP solution)
alpar@1
   673
*
alpar@1
   674
*  SYNOPSIS
alpar@1
   675
*
alpar@1
   676
*  double glp_mip_obj_val(glp_prob *mip);
alpar@1
   677
*
alpar@1
   678
*  RETURNS
alpar@1
   679
*
alpar@1
   680
*  The routine glp_mip_obj_val returns value of the objective function
alpar@1
   681
*  for MIP solution. */
alpar@1
   682
alpar@1
   683
double glp_mip_obj_val(glp_prob *mip)
alpar@1
   684
{     /*struct LPXCPS *cps = mip->cps;*/
alpar@1
   685
      double z;
alpar@1
   686
      z = mip->mip_obj;
alpar@1
   687
      /*if (cps->round && fabs(z) < 1e-9) z = 0.0;*/
alpar@1
   688
      return z;
alpar@1
   689
}
alpar@1
   690
alpar@1
   691
/***********************************************************************
alpar@1
   692
*  NAME
alpar@1
   693
*
alpar@1
   694
*  glp_mip_row_val - retrieve row value (MIP solution)
alpar@1
   695
*
alpar@1
   696
*  SYNOPSIS
alpar@1
   697
*
alpar@1
   698
*  double glp_mip_row_val(glp_prob *mip, int i);
alpar@1
   699
*
alpar@1
   700
*  RETURNS
alpar@1
   701
*
alpar@1
   702
*  The routine glp_mip_row_val returns value of the auxiliary variable
alpar@1
   703
*  associated with i-th row. */
alpar@1
   704
alpar@1
   705
double glp_mip_row_val(glp_prob *mip, int i)
alpar@1
   706
{     /*struct LPXCPS *cps = mip->cps;*/
alpar@1
   707
      double mipx;
alpar@1
   708
      if (!(1 <= i && i <= mip->m))
alpar@1
   709
         xerror("glp_mip_row_val: i = %d; row number out of range\n", i)
alpar@1
   710
            ;
alpar@1
   711
      mipx = mip->row[i]->mipx;
alpar@1
   712
      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
alpar@1
   713
      return mipx;
alpar@1
   714
}
alpar@1
   715
alpar@1
   716
/***********************************************************************
alpar@1
   717
*  NAME
alpar@1
   718
*
alpar@1
   719
*  glp_mip_col_val - retrieve column value (MIP solution)
alpar@1
   720
*
alpar@1
   721
*  SYNOPSIS
alpar@1
   722
*
alpar@1
   723
*  double glp_mip_col_val(glp_prob *mip, int j);
alpar@1
   724
*
alpar@1
   725
*  RETURNS
alpar@1
   726
*
alpar@1
   727
*  The routine glp_mip_col_val returns value of the structural variable
alpar@1
   728
*  associated with j-th column. */
alpar@1
   729
alpar@1
   730
double glp_mip_col_val(glp_prob *mip, int j)
alpar@1
   731
{     /*struct LPXCPS *cps = mip->cps;*/
alpar@1
   732
      double mipx;
alpar@1
   733
      if (!(1 <= j && j <= mip->n))
alpar@1
   734
         xerror("glp_mip_col_val: j = %d; column number out of range\n",
alpar@1
   735
            j);
alpar@1
   736
      mipx = mip->col[j]->mipx;
alpar@1
   737
      /*if (cps->round && fabs(mipx) < 1e-9) mipx = 0.0;*/
alpar@1
   738
      return mipx;
alpar@1
   739
}
alpar@1
   740
alpar@1
   741
/* eof */