src/glpapi13.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpapi13.c (branch-and-bound interface 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
alpar@1
    27
/***********************************************************************
alpar@1
    28
*  NAME
alpar@1
    29
*
alpar@1
    30
*  glp_ios_reason - determine reason for calling the callback routine
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  glp_ios_reason(glp_tree *tree);
alpar@1
    35
*
alpar@1
    36
*  RETURNS
alpar@1
    37
*
alpar@1
    38
*  The routine glp_ios_reason returns a code, which indicates why the
alpar@1
    39
*  user-defined callback routine is being called. */
alpar@1
    40
alpar@1
    41
int glp_ios_reason(glp_tree *tree)
alpar@1
    42
{     return
alpar@1
    43
         tree->reason;
alpar@1
    44
}
alpar@1
    45
alpar@1
    46
/***********************************************************************
alpar@1
    47
*  NAME
alpar@1
    48
*
alpar@1
    49
*  glp_ios_get_prob - access the problem object
alpar@1
    50
*
alpar@1
    51
*  SYNOPSIS
alpar@1
    52
*
alpar@1
    53
*  glp_prob *glp_ios_get_prob(glp_tree *tree);
alpar@1
    54
*
alpar@1
    55
*  DESCRIPTION
alpar@1
    56
*
alpar@1
    57
*  The routine glp_ios_get_prob can be called from the user-defined
alpar@1
    58
*  callback routine to access the problem object, which is used by the
alpar@1
    59
*  MIP solver. It is the original problem object passed to the routine
alpar@1
    60
*  glp_intopt if the MIP presolver is not used; otherwise it is an
alpar@1
    61
*  internal problem object built by the presolver. If the current
alpar@1
    62
*  subproblem exists, LP segment of the problem object corresponds to
alpar@1
    63
*  its LP relaxation.
alpar@1
    64
*
alpar@1
    65
*  RETURNS
alpar@1
    66
*
alpar@1
    67
*  The routine glp_ios_get_prob returns a pointer to the problem object
alpar@1
    68
*  used by the MIP solver. */
alpar@1
    69
alpar@1
    70
glp_prob *glp_ios_get_prob(glp_tree *tree)
alpar@1
    71
{     return
alpar@1
    72
         tree->mip;
alpar@1
    73
}
alpar@1
    74
alpar@1
    75
/***********************************************************************
alpar@1
    76
*  NAME
alpar@1
    77
*
alpar@1
    78
*  glp_ios_tree_size - determine size of the branch-and-bound tree
alpar@1
    79
*
alpar@1
    80
*  SYNOPSIS
alpar@1
    81
*
alpar@1
    82
*  void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
alpar@1
    83
*     int *t_cnt);
alpar@1
    84
*
alpar@1
    85
*  DESCRIPTION
alpar@1
    86
*
alpar@1
    87
*  The routine glp_ios_tree_size stores the following three counts which
alpar@1
    88
*  characterize the current size of the branch-and-bound tree:
alpar@1
    89
*
alpar@1
    90
*  a_cnt is the current number of active nodes, i.e. the current size of
alpar@1
    91
*        the active list;
alpar@1
    92
*
alpar@1
    93
*  n_cnt is the current number of all (active and inactive) nodes;
alpar@1
    94
*
alpar@1
    95
*  t_cnt is the total number of nodes including those which have been
alpar@1
    96
*        already removed from the tree. This count is increased whenever
alpar@1
    97
*        a new node appears in the tree and never decreased.
alpar@1
    98
*
alpar@1
    99
*  If some of the parameters a_cnt, n_cnt, t_cnt is a null pointer, the
alpar@1
   100
*  corresponding count is not stored. */
alpar@1
   101
alpar@1
   102
void glp_ios_tree_size(glp_tree *tree, int *a_cnt, int *n_cnt,
alpar@1
   103
      int *t_cnt)
alpar@1
   104
{     if (a_cnt != NULL) *a_cnt = tree->a_cnt;
alpar@1
   105
      if (n_cnt != NULL) *n_cnt = tree->n_cnt;
alpar@1
   106
      if (t_cnt != NULL) *t_cnt = tree->t_cnt;
alpar@1
   107
      return;
alpar@1
   108
}
alpar@1
   109
alpar@1
   110
/***********************************************************************
alpar@1
   111
*  NAME
alpar@1
   112
*
alpar@1
   113
*  glp_ios_curr_node - determine current active subproblem
alpar@1
   114
*
alpar@1
   115
*  SYNOPSIS
alpar@1
   116
*
alpar@1
   117
*  int glp_ios_curr_node(glp_tree *tree);
alpar@1
   118
*
alpar@1
   119
*  RETURNS
alpar@1
   120
*
alpar@1
   121
*  The routine glp_ios_curr_node returns the reference number of the
alpar@1
   122
*  current active subproblem. However, if the current subproblem does
alpar@1
   123
*  not exist, the routine returns zero. */
alpar@1
   124
alpar@1
   125
int glp_ios_curr_node(glp_tree *tree)
alpar@1
   126
{     IOSNPD *node;
alpar@1
   127
      /* obtain pointer to the current subproblem */
alpar@1
   128
      node = tree->curr;
alpar@1
   129
      /* return its reference number */
alpar@1
   130
      return node == NULL ? 0 : node->p;
alpar@1
   131
}
alpar@1
   132
alpar@1
   133
/***********************************************************************
alpar@1
   134
*  NAME
alpar@1
   135
*
alpar@1
   136
*  glp_ios_next_node - determine next active subproblem
alpar@1
   137
*
alpar@1
   138
*  SYNOPSIS
alpar@1
   139
*
alpar@1
   140
*  int glp_ios_next_node(glp_tree *tree, int p);
alpar@1
   141
*
alpar@1
   142
*  RETURNS
alpar@1
   143
*
alpar@1
   144
*  If the parameter p is zero, the routine glp_ios_next_node returns
alpar@1
   145
*  the reference number of the first active subproblem. However, if the
alpar@1
   146
*  tree is empty, zero is returned.
alpar@1
   147
*
alpar@1
   148
*  If the parameter p is not zero, it must specify the reference number
alpar@1
   149
*  of some active subproblem, in which case the routine returns the
alpar@1
   150
*  reference number of the next active subproblem. However, if there is
alpar@1
   151
*  no next active subproblem in the list, zero is returned.
alpar@1
   152
*
alpar@1
   153
*  All subproblems in the active list are ordered chronologically, i.e.
alpar@1
   154
*  subproblem A precedes subproblem B if A was created before B. */
alpar@1
   155
alpar@1
   156
int glp_ios_next_node(glp_tree *tree, int p)
alpar@1
   157
{     IOSNPD *node;
alpar@1
   158
      if (p == 0)
alpar@1
   159
      {  /* obtain pointer to the first active subproblem */
alpar@1
   160
         node = tree->head;
alpar@1
   161
      }
alpar@1
   162
      else
alpar@1
   163
      {  /* obtain pointer to the specified subproblem */
alpar@1
   164
         if (!(1 <= p && p <= tree->nslots))
alpar@1
   165
err:        xerror("glp_ios_next_node: p = %d; invalid subproblem refer"
alpar@1
   166
               "ence number\n", p);
alpar@1
   167
         node = tree->slot[p].node;
alpar@1
   168
         if (node == NULL) goto err;
alpar@1
   169
         /* the specified subproblem must be active */
alpar@1
   170
         if (node->count != 0)
alpar@1
   171
            xerror("glp_ios_next_node: p = %d; subproblem not in the ac"
alpar@1
   172
               "tive list\n", p);
alpar@1
   173
         /* obtain pointer to the next active subproblem */
alpar@1
   174
         node = node->next;
alpar@1
   175
      }
alpar@1
   176
      /* return the reference number */
alpar@1
   177
      return node == NULL ? 0 : node->p;
alpar@1
   178
}
alpar@1
   179
alpar@1
   180
/***********************************************************************
alpar@1
   181
*  NAME
alpar@1
   182
*
alpar@1
   183
*  glp_ios_prev_node - determine previous active subproblem
alpar@1
   184
*
alpar@1
   185
*  SYNOPSIS
alpar@1
   186
*
alpar@1
   187
*  int glp_ios_prev_node(glp_tree *tree, int p);
alpar@1
   188
*
alpar@1
   189
*  RETURNS
alpar@1
   190
*
alpar@1
   191
*  If the parameter p is zero, the routine glp_ios_prev_node returns
alpar@1
   192
*  the reference number of the last active subproblem. However, if the
alpar@1
   193
*  tree is empty, zero is returned.
alpar@1
   194
*
alpar@1
   195
*  If the parameter p is not zero, it must specify the reference number
alpar@1
   196
*  of some active subproblem, in which case the routine returns the
alpar@1
   197
*  reference number of the previous active subproblem. However, if there
alpar@1
   198
*  is no previous active subproblem in the list, zero is returned.
alpar@1
   199
*
alpar@1
   200
*  All subproblems in the active list are ordered chronologically, i.e.
alpar@1
   201
*  subproblem A precedes subproblem B if A was created before B. */
alpar@1
   202
alpar@1
   203
int glp_ios_prev_node(glp_tree *tree, int p)
alpar@1
   204
{     IOSNPD *node;
alpar@1
   205
      if (p == 0)
alpar@1
   206
      {  /* obtain pointer to the last active subproblem */
alpar@1
   207
         node = tree->tail;
alpar@1
   208
      }
alpar@1
   209
      else
alpar@1
   210
      {  /* obtain pointer to the specified subproblem */
alpar@1
   211
         if (!(1 <= p && p <= tree->nslots))
alpar@1
   212
err:        xerror("glp_ios_prev_node: p = %d; invalid subproblem refer"
alpar@1
   213
               "ence number\n", p);
alpar@1
   214
         node = tree->slot[p].node;
alpar@1
   215
         if (node == NULL) goto err;
alpar@1
   216
         /* the specified subproblem must be active */
alpar@1
   217
         if (node->count != 0)
alpar@1
   218
            xerror("glp_ios_prev_node: p = %d; subproblem not in the ac"
alpar@1
   219
               "tive list\n", p);
alpar@1
   220
         /* obtain pointer to the previous active subproblem */
alpar@1
   221
         node = node->prev;
alpar@1
   222
      }
alpar@1
   223
      /* return the reference number */
alpar@1
   224
      return node == NULL ? 0 : node->p;
alpar@1
   225
}
alpar@1
   226
alpar@1
   227
/***********************************************************************
alpar@1
   228
*  NAME
alpar@1
   229
*
alpar@1
   230
*  glp_ios_up_node - determine parent subproblem
alpar@1
   231
*
alpar@1
   232
*  SYNOPSIS
alpar@1
   233
*
alpar@1
   234
*  int glp_ios_up_node(glp_tree *tree, int p);
alpar@1
   235
*
alpar@1
   236
*  RETURNS
alpar@1
   237
*
alpar@1
   238
*  The parameter p must specify the reference number of some (active or
alpar@1
   239
*  inactive) subproblem, in which case the routine iet_get_up_node
alpar@1
   240
*  returns the reference number of its parent subproblem. However, if
alpar@1
   241
*  the specified subproblem is the root of the tree and, therefore, has
alpar@1
   242
*  no parent, the routine returns zero. */
alpar@1
   243
alpar@1
   244
int glp_ios_up_node(glp_tree *tree, int p)
alpar@1
   245
{     IOSNPD *node;
alpar@1
   246
      /* obtain pointer to the specified subproblem */
alpar@1
   247
      if (!(1 <= p && p <= tree->nslots))
alpar@1
   248
err:     xerror("glp_ios_up_node: p = %d; invalid subproblem reference "
alpar@1
   249
            "number\n", p);
alpar@1
   250
      node = tree->slot[p].node;
alpar@1
   251
      if (node == NULL) goto err;
alpar@1
   252
      /* obtain pointer to the parent subproblem */
alpar@1
   253
      node = node->up;
alpar@1
   254
      /* return the reference number */
alpar@1
   255
      return node == NULL ? 0 : node->p;
alpar@1
   256
}
alpar@1
   257
alpar@1
   258
/***********************************************************************
alpar@1
   259
*  NAME
alpar@1
   260
*
alpar@1
   261
*  glp_ios_node_level - determine subproblem level
alpar@1
   262
*
alpar@1
   263
*  SYNOPSIS
alpar@1
   264
*
alpar@1
   265
*  int glp_ios_node_level(glp_tree *tree, int p);
alpar@1
   266
*
alpar@1
   267
*  RETURNS
alpar@1
   268
*
alpar@1
   269
*  The routine glp_ios_node_level returns the level of the subproblem,
alpar@1
   270
*  whose reference number is p, in the branch-and-bound tree. (The root
alpar@1
   271
*  subproblem has level 0, and the level of any other subproblem is the
alpar@1
   272
*  level of its parent plus one.) */
alpar@1
   273
alpar@1
   274
int glp_ios_node_level(glp_tree *tree, int p)
alpar@1
   275
{     IOSNPD *node;
alpar@1
   276
      /* obtain pointer to the specified subproblem */
alpar@1
   277
      if (!(1 <= p && p <= tree->nslots))
alpar@1
   278
err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
alpar@1
   279
            "ce number\n", p);
alpar@1
   280
      node = tree->slot[p].node;
alpar@1
   281
      if (node == NULL) goto err;
alpar@1
   282
      /* return the node level */
alpar@1
   283
      return node->level;
alpar@1
   284
}
alpar@1
   285
alpar@1
   286
/***********************************************************************
alpar@1
   287
*  NAME
alpar@1
   288
*
alpar@1
   289
*  glp_ios_node_bound - determine subproblem local bound
alpar@1
   290
*
alpar@1
   291
*  SYNOPSIS
alpar@1
   292
*
alpar@1
   293
*  double glp_ios_node_bound(glp_tree *tree, int p);
alpar@1
   294
*
alpar@1
   295
*  RETURNS
alpar@1
   296
*
alpar@1
   297
*  The routine glp_ios_node_bound returns the local bound for (active or
alpar@1
   298
*  inactive) subproblem, whose reference number is p.
alpar@1
   299
*
alpar@1
   300
*  COMMENTS
alpar@1
   301
*
alpar@1
   302
*  The local bound for subproblem p is an lower (minimization) or upper
alpar@1
   303
*  (maximization) bound for integer optimal solution to this subproblem
alpar@1
   304
*  (not to the original problem). This bound is local in the sense that
alpar@1
   305
*  only subproblems in the subtree rooted at node p cannot have better
alpar@1
   306
*  integer feasible solutions.
alpar@1
   307
*
alpar@1
   308
*  On creating a subproblem (due to the branching step) its local bound
alpar@1
   309
*  is inherited from its parent and then may get only stronger (never
alpar@1
   310
*  weaker). For the root subproblem its local bound is initially set to
alpar@1
   311
*  -DBL_MAX (minimization) or +DBL_MAX (maximization) and then improved
alpar@1
   312
*  as the root LP relaxation has been solved.
alpar@1
   313
*
alpar@1
   314
*  Note that the local bound is not necessarily the optimal objective
alpar@1
   315
*  value to corresponding LP relaxation; it may be stronger. */
alpar@1
   316
alpar@1
   317
double glp_ios_node_bound(glp_tree *tree, int p)
alpar@1
   318
{     IOSNPD *node;
alpar@1
   319
      /* obtain pointer to the specified subproblem */
alpar@1
   320
      if (!(1 <= p && p <= tree->nslots))
alpar@1
   321
err:     xerror("glp_ios_node_bound: p = %d; invalid subproblem referen"
alpar@1
   322
            "ce number\n", p);
alpar@1
   323
      node = tree->slot[p].node;
alpar@1
   324
      if (node == NULL) goto err;
alpar@1
   325
      /* return the node local bound */
alpar@1
   326
      return node->bound;
alpar@1
   327
}
alpar@1
   328
alpar@1
   329
/***********************************************************************
alpar@1
   330
*  NAME
alpar@1
   331
*
alpar@1
   332
*  glp_ios_best_node - find active subproblem with best local bound
alpar@1
   333
*
alpar@1
   334
*  SYNOPSIS
alpar@1
   335
*
alpar@1
   336
*  int glp_ios_best_node(glp_tree *tree);
alpar@1
   337
*
alpar@1
   338
*  RETURNS
alpar@1
   339
*
alpar@1
   340
*  The routine glp_ios_best_node returns the reference number of the
alpar@1
   341
*  active subproblem, whose local bound is best (i.e. smallest in case
alpar@1
   342
*  of minimization or largest in case of maximization). However, if the
alpar@1
   343
*  tree is empty, the routine returns zero.
alpar@1
   344
*
alpar@1
   345
*  COMMENTS
alpar@1
   346
*
alpar@1
   347
*  The best local bound is an lower (minimization) or upper
alpar@1
   348
*  (maximization) bound for integer optimal solution to the original
alpar@1
   349
*  MIP problem. */
alpar@1
   350
alpar@1
   351
int glp_ios_best_node(glp_tree *tree)
alpar@1
   352
{     return
alpar@1
   353
         ios_best_node(tree);
alpar@1
   354
}
alpar@1
   355
alpar@1
   356
/***********************************************************************
alpar@1
   357
*  NAME
alpar@1
   358
*
alpar@1
   359
*  glp_ios_mip_gap - compute relative MIP gap
alpar@1
   360
*
alpar@1
   361
*  SYNOPSIS
alpar@1
   362
*
alpar@1
   363
*  double glp_ios_mip_gap(glp_tree *tree);
alpar@1
   364
*
alpar@1
   365
*  DESCRIPTION
alpar@1
   366
*
alpar@1
   367
*  The routine glp_ios_mip_gap computes the relative MIP gap with the
alpar@1
   368
*  following formula:
alpar@1
   369
*
alpar@1
   370
*     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
alpar@1
   371
*
alpar@1
   372
*  where best_mip is the best integer feasible solution found so far,
alpar@1
   373
*  best_bnd is the best (global) bound. If no integer feasible solution
alpar@1
   374
*  has been found yet, gap is set to DBL_MAX.
alpar@1
   375
*
alpar@1
   376
*  RETURNS
alpar@1
   377
*
alpar@1
   378
*  The routine glp_ios_mip_gap returns the relative MIP gap. */
alpar@1
   379
alpar@1
   380
double glp_ios_mip_gap(glp_tree *tree)
alpar@1
   381
{     return
alpar@1
   382
         ios_relative_gap(tree);
alpar@1
   383
}
alpar@1
   384
alpar@1
   385
/***********************************************************************
alpar@1
   386
*  NAME
alpar@1
   387
*
alpar@1
   388
*  glp_ios_node_data - access subproblem application-specific data
alpar@1
   389
*
alpar@1
   390
*  SYNOPSIS
alpar@1
   391
*
alpar@1
   392
*  void *glp_ios_node_data(glp_tree *tree, int p);
alpar@1
   393
*
alpar@1
   394
*  DESCRIPTION
alpar@1
   395
*
alpar@1
   396
*  The routine glp_ios_node_data allows the application accessing a
alpar@1
   397
*  memory block allocated for the subproblem (which may be active or
alpar@1
   398
*  inactive), whose reference number is p.
alpar@1
   399
*
alpar@1
   400
*  The size of the block is defined by the control parameter cb_size
alpar@1
   401
*  passed to the routine glp_intopt. The block is initialized by binary
alpar@1
   402
*  zeros on creating corresponding subproblem, and its contents is kept
alpar@1
   403
*  until the subproblem will be removed from the tree.
alpar@1
   404
*
alpar@1
   405
*  The application may use these memory blocks to store specific data
alpar@1
   406
*  for each subproblem.
alpar@1
   407
*
alpar@1
   408
*  RETURNS
alpar@1
   409
*
alpar@1
   410
*  The routine glp_ios_node_data returns a pointer to the memory block
alpar@1
   411
*  for the specified subproblem. Note that if cb_size = 0, the routine
alpar@1
   412
*  returns a null pointer. */
alpar@1
   413
alpar@1
   414
void *glp_ios_node_data(glp_tree *tree, int p)
alpar@1
   415
{     IOSNPD *node;
alpar@1
   416
      /* obtain pointer to the specified subproblem */
alpar@1
   417
      if (!(1 <= p && p <= tree->nslots))
alpar@1
   418
err:     xerror("glp_ios_node_level: p = %d; invalid subproblem referen"
alpar@1
   419
            "ce number\n", p);
alpar@1
   420
      node = tree->slot[p].node;
alpar@1
   421
      if (node == NULL) goto err;
alpar@1
   422
      /* return pointer to the application-specific data */
alpar@1
   423
      return node->data;
alpar@1
   424
}
alpar@1
   425
alpar@1
   426
/***********************************************************************
alpar@1
   427
*  NAME
alpar@1
   428
*
alpar@1
   429
*  glp_ios_row_attr - retrieve additional row attributes
alpar@1
   430
*
alpar@1
   431
*  SYNOPSIS
alpar@1
   432
*
alpar@1
   433
*  void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr);
alpar@1
   434
*
alpar@1
   435
*  DESCRIPTION
alpar@1
   436
*
alpar@1
   437
*  The routine glp_ios_row_attr retrieves additional attributes of row
alpar@1
   438
*  i and stores them in the structure glp_attr. */
alpar@1
   439
alpar@1
   440
void glp_ios_row_attr(glp_tree *tree, int i, glp_attr *attr)
alpar@1
   441
{     GLPROW *row;
alpar@1
   442
      if (!(1 <= i && i <= tree->mip->m))
alpar@1
   443
         xerror("glp_ios_row_attr: i = %d; row number out of range\n",
alpar@1
   444
            i);
alpar@1
   445
      row = tree->mip->row[i];
alpar@1
   446
      attr->level = row->level;
alpar@1
   447
      attr->origin = row->origin;
alpar@1
   448
      attr->klass = row->klass;
alpar@1
   449
      return;
alpar@1
   450
}
alpar@1
   451
alpar@1
   452
/**********************************************************************/
alpar@1
   453
alpar@1
   454
int glp_ios_pool_size(glp_tree *tree)
alpar@1
   455
{     /* determine current size of the cut pool */
alpar@1
   456
      if (tree->reason != GLP_ICUTGEN)
alpar@1
   457
         xerror("glp_ios_pool_size: operation not allowed\n");
alpar@1
   458
      xassert(tree->local != NULL);
alpar@1
   459
      return tree->local->size;
alpar@1
   460
}
alpar@1
   461
alpar@1
   462
/**********************************************************************/
alpar@1
   463
alpar@1
   464
int glp_ios_add_row(glp_tree *tree,
alpar@1
   465
      const char *name, int klass, int flags, int len, const int ind[],
alpar@1
   466
      const double val[], int type, double rhs)
alpar@1
   467
{     /* add row (constraint) to the cut pool */
alpar@1
   468
      int num;
alpar@1
   469
      if (tree->reason != GLP_ICUTGEN)
alpar@1
   470
         xerror("glp_ios_add_row: operation not allowed\n");
alpar@1
   471
      xassert(tree->local != NULL);
alpar@1
   472
      num = ios_add_row(tree, tree->local, name, klass, flags, len,
alpar@1
   473
         ind, val, type, rhs);
alpar@1
   474
      return num;
alpar@1
   475
}
alpar@1
   476
alpar@1
   477
/**********************************************************************/
alpar@1
   478
alpar@1
   479
void glp_ios_del_row(glp_tree *tree, int i)
alpar@1
   480
{     /* remove row (constraint) from the cut pool */
alpar@1
   481
      if (tree->reason != GLP_ICUTGEN)
alpar@1
   482
         xerror("glp_ios_del_row: operation not allowed\n");
alpar@1
   483
      ios_del_row(tree, tree->local, i);
alpar@1
   484
      return;
alpar@1
   485
}
alpar@1
   486
alpar@1
   487
/**********************************************************************/
alpar@1
   488
alpar@1
   489
void glp_ios_clear_pool(glp_tree *tree)
alpar@1
   490
{     /* remove all rows (constraints) from the cut pool */
alpar@1
   491
      if (tree->reason != GLP_ICUTGEN)
alpar@1
   492
         xerror("glp_ios_clear_pool: operation not allowed\n");
alpar@1
   493
      ios_clear_pool(tree, tree->local);
alpar@1
   494
      return;
alpar@1
   495
}
alpar@1
   496
alpar@1
   497
/***********************************************************************
alpar@1
   498
*  NAME
alpar@1
   499
*
alpar@1
   500
*  glp_ios_can_branch - check if can branch upon specified variable
alpar@1
   501
*
alpar@1
   502
*  SYNOPSIS
alpar@1
   503
*
alpar@1
   504
*  int glp_ios_can_branch(glp_tree *tree, int j);
alpar@1
   505
*
alpar@1
   506
*  RETURNS
alpar@1
   507
*
alpar@1
   508
*  If j-th variable (column) can be used to branch upon, the routine
alpar@1
   509
*  glp_ios_can_branch returns non-zero, otherwise zero. */
alpar@1
   510
alpar@1
   511
int glp_ios_can_branch(glp_tree *tree, int j)
alpar@1
   512
{     if (!(1 <= j && j <= tree->mip->n))
alpar@1
   513
         xerror("glp_ios_can_branch: j = %d; column number out of range"
alpar@1
   514
            "\n", j);
alpar@1
   515
      return tree->non_int[j];
alpar@1
   516
}
alpar@1
   517
alpar@1
   518
/***********************************************************************
alpar@1
   519
*  NAME
alpar@1
   520
*
alpar@1
   521
*  glp_ios_branch_upon - choose variable to branch upon
alpar@1
   522
*
alpar@1
   523
*  SYNOPSIS
alpar@1
   524
*
alpar@1
   525
*  void glp_ios_branch_upon(glp_tree *tree, int j, int sel);
alpar@1
   526
*
alpar@1
   527
*  DESCRIPTION
alpar@1
   528
*
alpar@1
   529
*  The routine glp_ios_branch_upon can be called from the user-defined
alpar@1
   530
*  callback routine in response to the reason GLP_IBRANCH to choose a
alpar@1
   531
*  branching variable, whose ordinal number is j. Should note that only
alpar@1
   532
*  variables, for which the routine glp_ios_can_branch returns non-zero,
alpar@1
   533
*  can be used to branch upon.
alpar@1
   534
*
alpar@1
   535
*  The parameter sel is a flag that indicates which branch (subproblem)
alpar@1
   536
*  should be selected next to continue the search:
alpar@1
   537
*
alpar@1
   538
*  GLP_DN_BRNCH - select down-branch;
alpar@1
   539
*  GLP_UP_BRNCH - select up-branch;
alpar@1
   540
*  GLP_NO_BRNCH - use general selection technique. */
alpar@1
   541
alpar@1
   542
void glp_ios_branch_upon(glp_tree *tree, int j, int sel)
alpar@1
   543
{     if (!(1 <= j && j <= tree->mip->n))
alpar@1
   544
         xerror("glp_ios_branch_upon: j = %d; column number out of rang"
alpar@1
   545
            "e\n", j);
alpar@1
   546
      if (!(sel == GLP_DN_BRNCH || sel == GLP_UP_BRNCH ||
alpar@1
   547
            sel == GLP_NO_BRNCH))
alpar@1
   548
         xerror("glp_ios_branch_upon: sel = %d: invalid branch selectio"
alpar@1
   549
            "n flag\n", sel);
alpar@1
   550
      if (!(tree->non_int[j]))
alpar@1
   551
         xerror("glp_ios_branch_upon: j = %d; variable cannot be used t"
alpar@1
   552
            "o branch upon\n", j);
alpar@1
   553
      if (tree->br_var != 0)
alpar@1
   554
         xerror("glp_ios_branch_upon: branching variable already chosen"
alpar@1
   555
            "\n");
alpar@1
   556
      tree->br_var = j;
alpar@1
   557
      tree->br_sel = sel;
alpar@1
   558
      return;
alpar@1
   559
}
alpar@1
   560
alpar@1
   561
/***********************************************************************
alpar@1
   562
*  NAME
alpar@1
   563
*
alpar@1
   564
*  glp_ios_select_node - select subproblem to continue the search
alpar@1
   565
*
alpar@1
   566
*  SYNOPSIS
alpar@1
   567
*
alpar@1
   568
*  void glp_ios_select_node(glp_tree *tree, int p);
alpar@1
   569
*
alpar@1
   570
*  DESCRIPTION
alpar@1
   571
*
alpar@1
   572
*  The routine glp_ios_select_node can be called from the user-defined
alpar@1
   573
*  callback routine in response to the reason GLP_ISELECT to select an
alpar@1
   574
*  active subproblem, whose reference number is p. The search will be
alpar@1
   575
*  continued from the subproblem selected. */
alpar@1
   576
alpar@1
   577
void glp_ios_select_node(glp_tree *tree, int p)
alpar@1
   578
{     IOSNPD *node;
alpar@1
   579
      /* obtain pointer to the specified subproblem */
alpar@1
   580
      if (!(1 <= p && p <= tree->nslots))
alpar@1
   581
err:     xerror("glp_ios_select_node: p = %d; invalid subproblem refere"
alpar@1
   582
            "nce number\n", p);
alpar@1
   583
      node = tree->slot[p].node;
alpar@1
   584
      if (node == NULL) goto err;
alpar@1
   585
      /* the specified subproblem must be active */
alpar@1
   586
      if (node->count != 0)
alpar@1
   587
         xerror("glp_ios_select_node: p = %d; subproblem not in the act"
alpar@1
   588
            "ive list\n", p);
alpar@1
   589
      /* no subproblem must be selected yet */
alpar@1
   590
      if (tree->next_p != 0)
alpar@1
   591
         xerror("glp_ios_select_node: subproblem already selected\n");
alpar@1
   592
      /* select the specified subproblem to continue the search */
alpar@1
   593
      tree->next_p = p;
alpar@1
   594
      return;
alpar@1
   595
}
alpar@1
   596
alpar@1
   597
/***********************************************************************
alpar@1
   598
*  NAME
alpar@1
   599
*
alpar@1
   600
*  glp_ios_heur_sol - provide solution found by heuristic
alpar@1
   601
*
alpar@1
   602
*  SYNOPSIS
alpar@1
   603
*
alpar@1
   604
*  int glp_ios_heur_sol(glp_tree *tree, const double x[]);
alpar@1
   605
*
alpar@1
   606
*  DESCRIPTION
alpar@1
   607
*
alpar@1
   608
*  The routine glp_ios_heur_sol can be called from the user-defined
alpar@1
   609
*  callback routine in response to the reason GLP_IHEUR to provide an
alpar@1
   610
*  integer feasible solution found by a primal heuristic.
alpar@1
   611
*
alpar@1
   612
*  Primal values of *all* variables (columns) found by the heuristic
alpar@1
   613
*  should be placed in locations x[1], ..., x[n], where n is the number
alpar@1
   614
*  of columns in the original problem object. Note that the routine
alpar@1
   615
*  glp_ios_heur_sol *does not* check primal feasibility of the solution
alpar@1
   616
*  provided.
alpar@1
   617
*
alpar@1
   618
*  Using the solution passed in the array x the routine computes value
alpar@1
   619
*  of the objective function. If the objective value is better than the
alpar@1
   620
*  best known integer feasible solution, the routine computes values of
alpar@1
   621
*  auxiliary variables (rows) and stores all solution components in the
alpar@1
   622
*  problem object.
alpar@1
   623
*
alpar@1
   624
*  RETURNS
alpar@1
   625
*
alpar@1
   626
*  If the provided solution is accepted, the routine glp_ios_heur_sol
alpar@1
   627
*  returns zero. Otherwise, if the provided solution is rejected, the
alpar@1
   628
*  routine returns non-zero. */
alpar@1
   629
alpar@1
   630
int glp_ios_heur_sol(glp_tree *tree, const double x[])
alpar@1
   631
{     glp_prob *mip = tree->mip;
alpar@1
   632
      int m = tree->orig_m;
alpar@1
   633
      int n = tree->n;
alpar@1
   634
      int i, j;
alpar@1
   635
      double obj;
alpar@1
   636
      xassert(mip->m >= m);
alpar@1
   637
      xassert(mip->n == n);
alpar@1
   638
      /* check values of integer variables and compute value of the
alpar@1
   639
         objective function */
alpar@1
   640
      obj = mip->c0;
alpar@1
   641
      for (j = 1; j <= n; j++)
alpar@1
   642
      {  GLPCOL *col = mip->col[j];
alpar@1
   643
         if (col->kind == GLP_IV)
alpar@1
   644
         {  /* provided value must be integral */
alpar@1
   645
            if (x[j] != floor(x[j])) return 1;
alpar@1
   646
         }
alpar@1
   647
         obj += col->coef * x[j];
alpar@1
   648
      }
alpar@1
   649
      /* check if the provided solution is better than the best known
alpar@1
   650
         integer feasible solution */
alpar@1
   651
      if (mip->mip_stat == GLP_FEAS)
alpar@1
   652
      {  switch (mip->dir)
alpar@1
   653
         {  case GLP_MIN:
alpar@1
   654
               if (obj >= tree->mip->mip_obj) return 1;
alpar@1
   655
               break;
alpar@1
   656
            case GLP_MAX:
alpar@1
   657
               if (obj <= tree->mip->mip_obj) return 1;
alpar@1
   658
               break;
alpar@1
   659
            default:
alpar@1
   660
               xassert(mip != mip);
alpar@1
   661
         }
alpar@1
   662
      }
alpar@1
   663
      /* it is better; store it in the problem object */
alpar@1
   664
      if (tree->parm->msg_lev >= GLP_MSG_ON)
alpar@1
   665
         xprintf("Solution found by heuristic: %.12g\n", obj);
alpar@1
   666
      mip->mip_stat = GLP_FEAS;
alpar@1
   667
      mip->mip_obj = obj;
alpar@1
   668
      for (j = 1; j <= n; j++)
alpar@1
   669
         mip->col[j]->mipx = x[j];
alpar@1
   670
      for (i = 1; i <= m; i++)
alpar@1
   671
      {  GLPROW *row = mip->row[i];
alpar@1
   672
         GLPAIJ *aij;
alpar@1
   673
         row->mipx = 0.0;
alpar@1
   674
         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
alpar@1
   675
            row->mipx += aij->val * aij->col->mipx;
alpar@1
   676
      }
alpar@1
   677
      return 0;
alpar@1
   678
}
alpar@1
   679
alpar@1
   680
/***********************************************************************
alpar@1
   681
*  NAME
alpar@1
   682
*
alpar@1
   683
*  glp_ios_terminate - terminate the solution process.
alpar@1
   684
*
alpar@1
   685
*  SYNOPSIS
alpar@1
   686
*
alpar@1
   687
*  void glp_ios_terminate(glp_tree *tree);
alpar@1
   688
*
alpar@1
   689
*  DESCRIPTION
alpar@1
   690
*
alpar@1
   691
*  The routine glp_ios_terminate sets a flag indicating that the MIP
alpar@1
   692
*  solver should prematurely terminate the search. */
alpar@1
   693
alpar@1
   694
void glp_ios_terminate(glp_tree *tree)
alpar@1
   695
{     if (tree->parm->msg_lev >= GLP_MSG_DBG)
alpar@1
   696
         xprintf("The search is prematurely terminated due to applicati"
alpar@1
   697
            "on request\n");
alpar@1
   698
      tree->stop = 1;
alpar@1
   699
      return;
alpar@1
   700
}
alpar@1
   701
alpar@1
   702
/* eof */