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