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