src/glpios01.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     1 /* glpios01.c */
     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 *  ios_create_tree - create branch-and-bound tree
    31 *
    32 *  SYNOPSIS
    33 *
    34 *  #include "glpios.h"
    35 *  glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm);
    36 *
    37 *  DESCRIPTION
    38 *
    39 *  The routine ios_create_tree creates the branch-and-bound tree.
    40 *
    41 *  Being created the tree consists of the only root subproblem whose
    42 *  reference number is 1. Note that initially the root subproblem is in
    43 *  frozen state and therefore needs to be revived.
    44 *
    45 *  RETURNS
    46 *
    47 *  The routine returns a pointer to the tree created. */
    48 
    49 static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent);
    50 
    51 glp_tree *ios_create_tree(glp_prob *mip, const glp_iocp *parm)
    52 {     int m = mip->m;
    53       int n = mip->n;
    54       glp_tree *tree;
    55       int i, j;
    56       xassert(mip->tree == NULL);
    57       mip->tree = tree = xmalloc(sizeof(glp_tree));
    58       tree->pool = dmp_create_pool();
    59       tree->n = n;
    60       /* save original problem components */
    61       tree->orig_m = m;
    62       tree->orig_type = xcalloc(1+m+n, sizeof(char));
    63       tree->orig_lb = xcalloc(1+m+n, sizeof(double));
    64       tree->orig_ub = xcalloc(1+m+n, sizeof(double));
    65       tree->orig_stat = xcalloc(1+m+n, sizeof(char));
    66       tree->orig_prim = xcalloc(1+m+n, sizeof(double));
    67       tree->orig_dual = xcalloc(1+m+n, sizeof(double));
    68       for (i = 1; i <= m; i++)
    69       {  GLPROW *row = mip->row[i];
    70          tree->orig_type[i] = (char)row->type;
    71          tree->orig_lb[i] = row->lb;
    72          tree->orig_ub[i] = row->ub;
    73          tree->orig_stat[i] = (char)row->stat;
    74          tree->orig_prim[i] = row->prim;
    75          tree->orig_dual[i] = row->dual;
    76       }
    77       for (j = 1; j <= n; j++)
    78       {  GLPCOL *col = mip->col[j];
    79          tree->orig_type[m+j] = (char)col->type;
    80          tree->orig_lb[m+j] = col->lb;
    81          tree->orig_ub[m+j] = col->ub;
    82          tree->orig_stat[m+j] = (char)col->stat;
    83          tree->orig_prim[m+j] = col->prim;
    84          tree->orig_dual[m+j] = col->dual;
    85       }
    86       tree->orig_obj = mip->obj_val;
    87       /* initialize the branch-and-bound tree */
    88       tree->nslots = 0;
    89       tree->avail = 0;
    90       tree->slot = NULL;
    91       tree->head = tree->tail = NULL;
    92       tree->a_cnt = tree->n_cnt = tree->t_cnt = 0;
    93       /* the root subproblem is not solved yet, so its final components
    94          are unknown so far */
    95       tree->root_m = 0;
    96       tree->root_type = NULL;
    97       tree->root_lb = tree->root_ub = NULL;
    98       tree->root_stat = NULL;
    99       /* the current subproblem does not exist yet */
   100       tree->curr = NULL;
   101       tree->mip = mip;
   102       /*tree->solved = 0;*/
   103       tree->non_int = xcalloc(1+n, sizeof(char));
   104       memset(&tree->non_int[1], 0, n);
   105       /* arrays to save parent subproblem components will be allocated
   106          later */
   107       tree->pred_m = tree->pred_max = 0;
   108       tree->pred_type = NULL;
   109       tree->pred_lb = tree->pred_ub = NULL;
   110       tree->pred_stat = NULL;
   111       /* cut generator */
   112       tree->local = ios_create_pool(tree);
   113       /*tree->first_attempt = 1;*/
   114       /*tree->max_added_cuts = 0;*/
   115       /*tree->min_eff = 0.0;*/
   116       /*tree->miss = 0;*/
   117       /*tree->just_selected = 0;*/
   118       tree->mir_gen = NULL;
   119       tree->clq_gen = NULL;
   120       /*tree->round = 0;*/
   121 #if 0
   122       /* create the conflict graph */
   123       tree->n_ref = xcalloc(1+n, sizeof(int));
   124       memset(&tree->n_ref[1], 0, n * sizeof(int));
   125       tree->c_ref = xcalloc(1+n, sizeof(int));
   126       memset(&tree->c_ref[1], 0, n * sizeof(int));
   127       tree->g = scg_create_graph(0);
   128       tree->j_ref = xcalloc(1+tree->g->n_max, sizeof(int));
   129 #endif
   130       /* pseudocost branching */
   131       tree->pcost = NULL;
   132       tree->iwrk = xcalloc(1+n, sizeof(int));
   133       tree->dwrk = xcalloc(1+n, sizeof(double));
   134       /* initialize control parameters */
   135       tree->parm = parm;
   136       tree->tm_beg = xtime();
   137       tree->tm_lag = xlset(0);
   138       tree->sol_cnt = 0;
   139       /* initialize advanced solver interface */
   140       tree->reason = 0;
   141       tree->reopt = 0;
   142       tree->reinv = 0;
   143       tree->br_var = 0;
   144       tree->br_sel = 0;
   145       tree->child = 0;
   146       tree->next_p = 0;
   147       /*tree->btrack = NULL;*/
   148       tree->stop = 0;
   149       /* create the root subproblem, which initially is identical to
   150          the original MIP */
   151       new_node(tree, NULL);
   152       return tree;
   153 }
   154 
   155 /***********************************************************************
   156 *  NAME
   157 *
   158 *  ios_revive_node - revive specified subproblem
   159 *
   160 *  SYNOPSIS
   161 *
   162 *  #include "glpios.h"
   163 *  void ios_revive_node(glp_tree *tree, int p);
   164 *
   165 *  DESCRIPTION
   166 *
   167 *  The routine ios_revive_node revives the specified subproblem, whose
   168 *  reference number is p, and thereby makes it the current subproblem.
   169 *  Note that the specified subproblem must be active. Besides, if the
   170 *  current subproblem already exists, it must be frozen before reviving
   171 *  another subproblem. */
   172 
   173 void ios_revive_node(glp_tree *tree, int p)
   174 {     glp_prob *mip = tree->mip;
   175       IOSNPD *node, *root;
   176       /* obtain pointer to the specified subproblem */
   177       xassert(1 <= p && p <= tree->nslots);
   178       node = tree->slot[p].node;
   179       xassert(node != NULL);
   180       /* the specified subproblem must be active */
   181       xassert(node->count == 0);
   182       /* the current subproblem must not exist */
   183       xassert(tree->curr == NULL);
   184       /* the specified subproblem becomes current */
   185       tree->curr = node;
   186       /*tree->solved = 0;*/
   187       /* obtain pointer to the root subproblem */
   188       root = tree->slot[1].node;
   189       xassert(root != NULL);
   190       /* at this point problem object components correspond to the root
   191          subproblem, so if the root subproblem should be revived, there
   192          is nothing more to do */
   193       if (node == root) goto done;
   194       xassert(mip->m == tree->root_m);
   195       /* build path from the root to the current node */
   196       node->temp = NULL;
   197       for (node = node; node != NULL; node = node->up)
   198       {  if (node->up == NULL)
   199             xassert(node == root);
   200          else
   201             node->up->temp = node;
   202       }
   203       /* go down from the root to the current node and make necessary
   204          changes to restore components of the current subproblem */
   205       for (node = root; node != NULL; node = node->temp)
   206       {  int m = mip->m;
   207          int n = mip->n;
   208          /* if the current node is reached, the problem object at this
   209             point corresponds to its parent, so save attributes of rows
   210             and columns for the parent subproblem */
   211          if (node->temp == NULL)
   212          {  int i, j;
   213             tree->pred_m = m;
   214             /* allocate/reallocate arrays, if necessary */
   215             if (tree->pred_max < m + n)
   216             {  int new_size = m + n + 100;
   217                if (tree->pred_type != NULL) xfree(tree->pred_type);
   218                if (tree->pred_lb != NULL) xfree(tree->pred_lb);
   219                if (tree->pred_ub != NULL) xfree(tree->pred_ub);
   220                if (tree->pred_stat != NULL) xfree(tree->pred_stat);
   221                tree->pred_max = new_size;
   222                tree->pred_type = xcalloc(1+new_size, sizeof(char));
   223                tree->pred_lb = xcalloc(1+new_size, sizeof(double));
   224                tree->pred_ub = xcalloc(1+new_size, sizeof(double));
   225                tree->pred_stat = xcalloc(1+new_size, sizeof(char));
   226             }
   227             /* save row attributes */
   228             for (i = 1; i <= m; i++)
   229             {  GLPROW *row = mip->row[i];
   230                tree->pred_type[i] = (char)row->type;
   231                tree->pred_lb[i] = row->lb;
   232                tree->pred_ub[i] = row->ub;
   233                tree->pred_stat[i] = (char)row->stat;
   234             }
   235             /* save column attributes */
   236             for (j = 1; j <= n; j++)
   237             {  GLPCOL *col = mip->col[j];
   238                tree->pred_type[mip->m+j] = (char)col->type;
   239                tree->pred_lb[mip->m+j] = col->lb;
   240                tree->pred_ub[mip->m+j] = col->ub;
   241                tree->pred_stat[mip->m+j] = (char)col->stat;
   242             }
   243          }
   244          /* change bounds of rows and columns */
   245          {  IOSBND *b;
   246             for (b = node->b_ptr; b != NULL; b = b->next)
   247             {  if (b->k <= m)
   248                   glp_set_row_bnds(mip, b->k, b->type, b->lb, b->ub);
   249                else
   250                   glp_set_col_bnds(mip, b->k-m, b->type, b->lb, b->ub);
   251             }
   252          }
   253          /* change statuses of rows and columns */
   254          {  IOSTAT *s;
   255             for (s = node->s_ptr; s != NULL; s = s->next)
   256             {  if (s->k <= m)
   257                   glp_set_row_stat(mip, s->k, s->stat);
   258                else
   259                   glp_set_col_stat(mip, s->k-m, s->stat);
   260             }
   261          }
   262          /* add new rows */
   263          if (node->r_ptr != NULL)
   264          {  IOSROW *r;
   265             IOSAIJ *a;
   266             int i, len, *ind;
   267             double *val;
   268             ind = xcalloc(1+n, sizeof(int));
   269             val = xcalloc(1+n, sizeof(double));
   270             for (r = node->r_ptr; r != NULL; r = r->next)
   271             {  i = glp_add_rows(mip, 1);
   272                glp_set_row_name(mip, i, r->name);
   273 #if 1 /* 20/IX-2008 */
   274                xassert(mip->row[i]->level == 0);
   275                mip->row[i]->level = node->level;
   276                mip->row[i]->origin = r->origin;
   277                mip->row[i]->klass = r->klass;
   278 #endif
   279                glp_set_row_bnds(mip, i, r->type, r->lb, r->ub);
   280                len = 0;
   281                for (a = r->ptr; a != NULL; a = a->next)
   282                   len++, ind[len] = a->j, val[len] = a->val;
   283                glp_set_mat_row(mip, i, len, ind, val);
   284                glp_set_rii(mip, i, r->rii);
   285                glp_set_row_stat(mip, i, r->stat);
   286             }
   287             xfree(ind);
   288             xfree(val);
   289          }
   290 #if 0
   291          /* add new edges to the conflict graph */
   292          /* add new cliques to the conflict graph */
   293          /* (not implemented yet) */
   294          xassert(node->own_nn == 0);
   295          xassert(node->own_nc == 0);
   296          xassert(node->e_ptr == NULL);
   297 #endif
   298       }
   299       /* the specified subproblem has been revived */
   300       node = tree->curr;
   301       /* delete its bound change list */
   302       while (node->b_ptr != NULL)
   303       {  IOSBND *b;
   304          b = node->b_ptr;
   305          node->b_ptr = b->next;
   306          dmp_free_atom(tree->pool, b, sizeof(IOSBND));
   307       }
   308       /* delete its status change list */
   309       while (node->s_ptr != NULL)
   310       {  IOSTAT *s;
   311          s = node->s_ptr;
   312          node->s_ptr = s->next;
   313          dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
   314       }
   315 #if 1 /* 20/XI-2009 */
   316       /* delete its row addition list (additional rows may appear, for
   317          example, due to branching on GUB constraints */
   318       while (node->r_ptr != NULL)
   319       {  IOSROW *r;
   320          r = node->r_ptr;
   321          node->r_ptr = r->next;
   322          xassert(r->name == NULL);
   323          while (r->ptr != NULL)
   324          {  IOSAIJ *a;
   325             a = r->ptr;
   326             r->ptr = a->next;
   327             dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
   328          }
   329          dmp_free_atom(tree->pool, r, sizeof(IOSROW));
   330       }
   331 #endif
   332 done: return;
   333 }
   334 
   335 /***********************************************************************
   336 *  NAME
   337 *
   338 *  ios_freeze_node - freeze current subproblem
   339 *
   340 *  SYNOPSIS
   341 *
   342 *  #include "glpios.h"
   343 *  void ios_freeze_node(glp_tree *tree);
   344 *
   345 *  DESCRIPTION
   346 *
   347 *  The routine ios_freeze_node freezes the current subproblem. */
   348 
   349 void ios_freeze_node(glp_tree *tree)
   350 {     glp_prob *mip = tree->mip;
   351       int m = mip->m;
   352       int n = mip->n;
   353       IOSNPD *node;
   354       /* obtain pointer to the current subproblem */
   355       node = tree->curr;
   356       xassert(node != NULL);
   357       if (node->up == NULL)
   358       {  /* freeze the root subproblem */
   359          int k;
   360          xassert(node->p == 1);
   361          xassert(tree->root_m == 0);
   362          xassert(tree->root_type == NULL);
   363          xassert(tree->root_lb == NULL);
   364          xassert(tree->root_ub == NULL);
   365          xassert(tree->root_stat == NULL);
   366          tree->root_m = m;
   367          tree->root_type = xcalloc(1+m+n, sizeof(char));
   368          tree->root_lb = xcalloc(1+m+n, sizeof(double));
   369          tree->root_ub = xcalloc(1+m+n, sizeof(double));
   370          tree->root_stat = xcalloc(1+m+n, sizeof(char));
   371          for (k = 1; k <= m+n; k++)
   372          {  if (k <= m)
   373             {  GLPROW *row = mip->row[k];
   374                tree->root_type[k] = (char)row->type;
   375                tree->root_lb[k] = row->lb;
   376                tree->root_ub[k] = row->ub;
   377                tree->root_stat[k] = (char)row->stat;
   378             }
   379             else
   380             {  GLPCOL *col = mip->col[k-m];
   381                tree->root_type[k] = (char)col->type;
   382                tree->root_lb[k] = col->lb;
   383                tree->root_ub[k] = col->ub;
   384                tree->root_stat[k] = (char)col->stat;
   385             }
   386          }
   387       }
   388       else
   389       {  /* freeze non-root subproblem */
   390          int root_m = tree->root_m;
   391          int pred_m = tree->pred_m;
   392          int i, j, k;
   393          xassert(pred_m <= m);
   394          /* build change lists for rows and columns which exist in the
   395             parent subproblem */
   396          xassert(node->b_ptr == NULL);
   397          xassert(node->s_ptr == NULL);
   398          for (k = 1; k <= pred_m + n; k++)
   399          {  int pred_type, pred_stat, type, stat;
   400             double pred_lb, pred_ub, lb, ub;
   401             /* determine attributes in the parent subproblem */
   402             pred_type = tree->pred_type[k];
   403             pred_lb = tree->pred_lb[k];
   404             pred_ub = tree->pred_ub[k];
   405             pred_stat = tree->pred_stat[k];
   406             /* determine attributes in the current subproblem */
   407             if (k <= pred_m)
   408             {  GLPROW *row = mip->row[k];
   409                type = row->type;
   410                lb = row->lb;
   411                ub = row->ub;
   412                stat = row->stat;
   413             }
   414             else
   415             {  GLPCOL *col = mip->col[k - pred_m];
   416                type = col->type;
   417                lb = col->lb;
   418                ub = col->ub;
   419                stat = col->stat;
   420             }
   421             /* save type and bounds of a row/column, if changed */
   422             if (!(pred_type == type && pred_lb == lb && pred_ub == ub))
   423             {  IOSBND *b;
   424                b = dmp_get_atom(tree->pool, sizeof(IOSBND));
   425                b->k = k;
   426                b->type = (unsigned char)type;
   427                b->lb = lb;
   428                b->ub = ub;
   429                b->next = node->b_ptr;
   430                node->b_ptr = b;
   431             }
   432             /* save status of a row/column, if changed */
   433             if (pred_stat != stat)
   434             {  IOSTAT *s;
   435                s = dmp_get_atom(tree->pool, sizeof(IOSTAT));
   436                s->k = k;
   437                s->stat = (unsigned char)stat;
   438                s->next = node->s_ptr;
   439                node->s_ptr = s;
   440             }
   441          }
   442          /* save new rows added to the current subproblem */
   443          xassert(node->r_ptr == NULL);
   444          if (pred_m < m)
   445          {  int i, len, *ind;
   446             double *val;
   447             ind = xcalloc(1+n, sizeof(int));
   448             val = xcalloc(1+n, sizeof(double));
   449             for (i = m; i > pred_m; i--)
   450             {  GLPROW *row = mip->row[i];
   451                IOSROW *r;
   452                const char *name;
   453                r = dmp_get_atom(tree->pool, sizeof(IOSROW));
   454                name = glp_get_row_name(mip, i);
   455                if (name == NULL)
   456                   r->name = NULL;
   457                else
   458                {  r->name = dmp_get_atom(tree->pool, strlen(name)+1);
   459                   strcpy(r->name, name);
   460                }
   461 #if 1 /* 20/IX-2008 */
   462                r->origin = row->origin;
   463                r->klass = row->klass;
   464 #endif
   465                r->type = (unsigned char)row->type;
   466                r->lb = row->lb;
   467                r->ub = row->ub;
   468                r->ptr = NULL;
   469                len = glp_get_mat_row(mip, i, ind, val);
   470                for (k = 1; k <= len; k++)
   471                {  IOSAIJ *a;
   472                   a = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
   473                   a->j = ind[k];
   474                   a->val = val[k];
   475                   a->next = r->ptr;
   476                   r->ptr = a;
   477                }
   478                r->rii = row->rii;
   479                r->stat = (unsigned char)row->stat;
   480                r->next = node->r_ptr;
   481                node->r_ptr = r;
   482             }
   483             xfree(ind);
   484             xfree(val);
   485          }
   486          /* remove all rows missing in the root subproblem */
   487          if (m != root_m)
   488          {  int nrs, *num;
   489             nrs = m - root_m;
   490             xassert(nrs > 0);
   491             num = xcalloc(1+nrs, sizeof(int));
   492             for (i = 1; i <= nrs; i++) num[i] = root_m + i;
   493             glp_del_rows(mip, nrs, num);
   494             xfree(num);
   495          }
   496          m = mip->m;
   497          /* and restore attributes of all rows and columns for the root
   498             subproblem */
   499          xassert(m == root_m);
   500          for (i = 1; i <= m; i++)
   501          {  glp_set_row_bnds(mip, i, tree->root_type[i],
   502                tree->root_lb[i], tree->root_ub[i]);
   503             glp_set_row_stat(mip, i, tree->root_stat[i]);
   504          }
   505          for (j = 1; j <= n; j++)
   506          {  glp_set_col_bnds(mip, j, tree->root_type[m+j],
   507                tree->root_lb[m+j], tree->root_ub[m+j]);
   508             glp_set_col_stat(mip, j, tree->root_stat[m+j]);
   509          }
   510 #if 1
   511          /* remove all edges and cliques missing in the conflict graph
   512             for the root subproblem */
   513          /* (not implemented yet) */
   514 #endif
   515       }
   516       /* the current subproblem has been frozen */
   517       tree->curr = NULL;
   518       return;
   519 }
   520 
   521 /***********************************************************************
   522 *  NAME
   523 *
   524 *  ios_clone_node - clone specified subproblem
   525 *
   526 *  SYNOPSIS
   527 *
   528 *  #include "glpios.h"
   529 *  void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[]);
   530 *
   531 *  DESCRIPTION
   532 *
   533 *  The routine ios_clone_node clones the specified subproblem, whose
   534 *  reference number is p, creating its nnn exact copies. Note that the
   535 *  specified subproblem must be active and must be in the frozen state
   536 *  (i.e. it must not be the current subproblem).
   537 *
   538 *  Each clone, an exact copy of the specified subproblem, becomes a new
   539 *  active subproblem added to the end of the active list. After cloning
   540 *  the specified subproblem becomes inactive.
   541 *
   542 *  The reference numbers of clone subproblems are stored to locations
   543 *  ref[1], ..., ref[nnn]. */
   544 
   545 static int get_slot(glp_tree *tree)
   546 {     int p;
   547       /* if no free slots are available, increase the room */
   548       if (tree->avail == 0)
   549       {  int nslots = tree->nslots;
   550          IOSLOT *save = tree->slot;
   551          if (nslots == 0)
   552             tree->nslots = 20;
   553          else
   554          {  tree->nslots = nslots + nslots;
   555             xassert(tree->nslots > nslots);
   556          }
   557          tree->slot = xcalloc(1+tree->nslots, sizeof(IOSLOT));
   558          if (save != NULL)
   559          {  memcpy(&tree->slot[1], &save[1], nslots * sizeof(IOSLOT));
   560             xfree(save);
   561          }
   562          /* push more free slots into the stack */
   563          for (p = tree->nslots; p > nslots; p--)
   564          {  tree->slot[p].node = NULL;
   565             tree->slot[p].next = tree->avail;
   566             tree->avail = p;
   567          }
   568       }
   569       /* pull a free slot from the stack */
   570       p = tree->avail;
   571       tree->avail = tree->slot[p].next;
   572       xassert(tree->slot[p].node == NULL);
   573       tree->slot[p].next = 0;
   574       return p;
   575 }
   576 
   577 static IOSNPD *new_node(glp_tree *tree, IOSNPD *parent)
   578 {     IOSNPD *node;
   579       int p;
   580       /* pull a free slot for the new node */
   581       p = get_slot(tree);
   582       /* create descriptor of the new subproblem */
   583       node = dmp_get_atom(tree->pool, sizeof(IOSNPD));
   584       tree->slot[p].node = node;
   585       node->p = p;
   586       node->up = parent;
   587       node->level = (parent == NULL ? 0 : parent->level + 1);
   588       node->count = 0;
   589       node->b_ptr = NULL;
   590       node->s_ptr = NULL;
   591       node->r_ptr = NULL;
   592       node->solved = 0;
   593 #if 0
   594       node->own_nn = node->own_nc = 0;
   595       node->e_ptr = NULL;
   596 #endif
   597 #if 1 /* 04/X-2008 */
   598       node->lp_obj = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
   599          -DBL_MAX : +DBL_MAX) : parent->lp_obj);
   600 #endif
   601       node->bound = (parent == NULL ? (tree->mip->dir == GLP_MIN ?
   602          -DBL_MAX : +DBL_MAX) : parent->bound);
   603       node->br_var = 0;
   604       node->br_val = 0.0;
   605       node->ii_cnt = 0;
   606       node->ii_sum = 0.0;
   607 #if 1 /* 30/XI-2009 */
   608       node->changed = 0;
   609 #endif
   610       if (tree->parm->cb_size == 0)
   611          node->data = NULL;
   612       else
   613       {  node->data = dmp_get_atom(tree->pool, tree->parm->cb_size);
   614          memset(node->data, 0, tree->parm->cb_size);
   615       }
   616       node->temp = NULL;
   617       node->prev = tree->tail;
   618       node->next = NULL;
   619       /* add the new subproblem to the end of the active list */
   620       if (tree->head == NULL)
   621          tree->head = node;
   622       else
   623          tree->tail->next = node;
   624       tree->tail = node;
   625       tree->a_cnt++;
   626       tree->n_cnt++;
   627       tree->t_cnt++;
   628       /* increase the number of child subproblems */
   629       if (parent == NULL)
   630          xassert(p == 1);
   631       else
   632          parent->count++;
   633       return node;
   634 }
   635 
   636 void ios_clone_node(glp_tree *tree, int p, int nnn, int ref[])
   637 {     IOSNPD *node;
   638       int k;
   639       /* obtain pointer to the subproblem to be cloned */
   640       xassert(1 <= p && p <= tree->nslots);
   641       node = tree->slot[p].node;
   642       xassert(node != NULL);
   643       /* the specified subproblem must be active */
   644       xassert(node->count == 0);
   645       /* and must be in the frozen state */
   646       xassert(tree->curr != node);
   647       /* remove the specified subproblem from the active list, because
   648          it becomes inactive */
   649       if (node->prev == NULL)
   650          tree->head = node->next;
   651       else
   652          node->prev->next = node->next;
   653       if (node->next == NULL)
   654          tree->tail = node->prev;
   655       else
   656          node->next->prev = node->prev;
   657       node->prev = node->next = NULL;
   658       tree->a_cnt--;
   659       /* create clone subproblems */
   660       xassert(nnn > 0);
   661       for (k = 1; k <= nnn; k++)
   662          ref[k] = new_node(tree, node)->p;
   663       return;
   664 }
   665 
   666 /***********************************************************************
   667 *  NAME
   668 *
   669 *  ios_delete_node - delete specified subproblem
   670 *
   671 *  SYNOPSIS
   672 *
   673 *  #include "glpios.h"
   674 *  void ios_delete_node(glp_tree *tree, int p);
   675 *
   676 *  DESCRIPTION
   677 *
   678 *  The routine ios_delete_node deletes the specified subproblem, whose
   679 *  reference number is p. The subproblem must be active and must be in
   680 *  the frozen state (i.e. it must not be the current subproblem).
   681 *
   682 *  Note that deletion is performed recursively, i.e. if a subproblem to
   683 *  be deleted is the only child of its parent, the parent subproblem is
   684 *  also deleted, etc. */
   685 
   686 void ios_delete_node(glp_tree *tree, int p)
   687 {     IOSNPD *node, *temp;
   688       /* obtain pointer to the subproblem to be deleted */
   689       xassert(1 <= p && p <= tree->nslots);
   690       node = tree->slot[p].node;
   691       xassert(node != NULL);
   692       /* the specified subproblem must be active */
   693       xassert(node->count == 0);
   694       /* and must be in the frozen state */
   695       xassert(tree->curr != node);
   696       /* remove the specified subproblem from the active list, because
   697          it is gone from the tree */
   698       if (node->prev == NULL)
   699          tree->head = node->next;
   700       else
   701          node->prev->next = node->next;
   702       if (node->next == NULL)
   703          tree->tail = node->prev;
   704       else
   705          node->next->prev = node->prev;
   706       node->prev = node->next = NULL;
   707       tree->a_cnt--;
   708 loop: /* recursive deletion starts here */
   709       /* delete the bound change list */
   710       {  IOSBND *b;
   711          while (node->b_ptr != NULL)
   712          {  b = node->b_ptr;
   713             node->b_ptr = b->next;
   714             dmp_free_atom(tree->pool, b, sizeof(IOSBND));
   715          }
   716       }
   717       /* delete the status change list */
   718       {  IOSTAT *s;
   719          while (node->s_ptr != NULL)
   720          {  s = node->s_ptr;
   721             node->s_ptr = s->next;
   722             dmp_free_atom(tree->pool, s, sizeof(IOSTAT));
   723          }
   724       }
   725       /* delete the row addition list */
   726       while (node->r_ptr != NULL)
   727       {  IOSROW *r;
   728          r = node->r_ptr;
   729          if (r->name != NULL)
   730             dmp_free_atom(tree->pool, r->name, strlen(r->name)+1);
   731          while (r->ptr != NULL)
   732          {  IOSAIJ *a;
   733             a = r->ptr;
   734             r->ptr = a->next;
   735             dmp_free_atom(tree->pool, a, sizeof(IOSAIJ));
   736          }
   737          node->r_ptr = r->next;
   738          dmp_free_atom(tree->pool, r, sizeof(IOSROW));
   739       }
   740 #if 0
   741       /* delete the edge addition list */
   742       /* delete the clique addition list */
   743       /* (not implemented yet) */
   744       xassert(node->own_nn == 0);
   745       xassert(node->own_nc == 0);
   746       xassert(node->e_ptr == NULL);
   747 #endif
   748       /* free application-specific data */
   749       if (tree->parm->cb_size == 0)
   750          xassert(node->data == NULL);
   751       else
   752          dmp_free_atom(tree->pool, node->data, tree->parm->cb_size);
   753       /* free the corresponding node slot */
   754       p = node->p;
   755       xassert(tree->slot[p].node == node);
   756       tree->slot[p].node = NULL;
   757       tree->slot[p].next = tree->avail;
   758       tree->avail = p;
   759       /* save pointer to the parent subproblem */
   760       temp = node->up;
   761       /* delete the subproblem descriptor */
   762       dmp_free_atom(tree->pool, node, sizeof(IOSNPD));
   763       tree->n_cnt--;
   764       /* take pointer to the parent subproblem */
   765       node = temp;
   766       if (node != NULL)
   767       {  /* the parent subproblem exists; decrease the number of its
   768             child subproblems */
   769          xassert(node->count > 0);
   770          node->count--;
   771          /* if now the parent subproblem has no childs, it also must be
   772             deleted */
   773          if (node->count == 0) goto loop;
   774       }
   775       return;
   776 }
   777 
   778 /***********************************************************************
   779 *  NAME
   780 *
   781 *  ios_delete_tree - delete branch-and-bound tree
   782 *
   783 *  SYNOPSIS
   784 *
   785 *  #include "glpios.h"
   786 *  void ios_delete_tree(glp_tree *tree);
   787 *
   788 *  DESCRIPTION
   789 *
   790 *  The routine ios_delete_tree deletes the branch-and-bound tree, which
   791 *  the parameter tree points to, and frees all the memory allocated to
   792 *  this program object.
   793 *
   794 *  On exit components of the problem object are restored to correspond
   795 *  to the original MIP passed to the routine ios_create_tree. */
   796 
   797 void ios_delete_tree(glp_tree *tree)
   798 {     glp_prob *mip = tree->mip;
   799       int i, j;
   800       int m = mip->m;
   801       int n = mip->n;
   802       xassert(mip->tree == tree);
   803       /* remove all additional rows */
   804       if (m != tree->orig_m)
   805       {  int nrs, *num;
   806          nrs = m - tree->orig_m;
   807          xassert(nrs > 0);
   808          num = xcalloc(1+nrs, sizeof(int));
   809          for (i = 1; i <= nrs; i++) num[i] = tree->orig_m + i;
   810          glp_del_rows(mip, nrs, num);
   811          xfree(num);
   812       }
   813       m = tree->orig_m;
   814       /* restore original attributes of rows and columns */
   815       xassert(m == tree->orig_m);
   816       xassert(n == tree->n);
   817       for (i = 1; i <= m; i++)
   818       {  glp_set_row_bnds(mip, i, tree->orig_type[i],
   819             tree->orig_lb[i], tree->orig_ub[i]);
   820          glp_set_row_stat(mip, i, tree->orig_stat[i]);
   821          mip->row[i]->prim = tree->orig_prim[i];
   822          mip->row[i]->dual = tree->orig_dual[i];
   823       }
   824       for (j = 1; j <= n; j++)
   825       {  glp_set_col_bnds(mip, j, tree->orig_type[m+j],
   826             tree->orig_lb[m+j], tree->orig_ub[m+j]);
   827          glp_set_col_stat(mip, j, tree->orig_stat[m+j]);
   828          mip->col[j]->prim = tree->orig_prim[m+j];
   829          mip->col[j]->dual = tree->orig_dual[m+j];
   830       }
   831       mip->pbs_stat = mip->dbs_stat = GLP_FEAS;
   832       mip->obj_val = tree->orig_obj;
   833       /* delete the branch-and-bound tree */
   834       xassert(tree->local != NULL);
   835       ios_delete_pool(tree, tree->local);
   836       dmp_delete_pool(tree->pool);
   837       xfree(tree->orig_type);
   838       xfree(tree->orig_lb);
   839       xfree(tree->orig_ub);
   840       xfree(tree->orig_stat);
   841       xfree(tree->orig_prim);
   842       xfree(tree->orig_dual);
   843       xfree(tree->slot);
   844       if (tree->root_type != NULL) xfree(tree->root_type);
   845       if (tree->root_lb != NULL) xfree(tree->root_lb);
   846       if (tree->root_ub != NULL) xfree(tree->root_ub);
   847       if (tree->root_stat != NULL) xfree(tree->root_stat);
   848       xfree(tree->non_int);
   849 #if 0
   850       xfree(tree->n_ref);
   851       xfree(tree->c_ref);
   852       xfree(tree->j_ref);
   853 #endif
   854       if (tree->pcost != NULL) ios_pcost_free(tree);
   855       xfree(tree->iwrk);
   856       xfree(tree->dwrk);
   857 #if 0
   858       scg_delete_graph(tree->g);
   859 #endif
   860       if (tree->pred_type != NULL) xfree(tree->pred_type);
   861       if (tree->pred_lb != NULL) xfree(tree->pred_lb);
   862       if (tree->pred_ub != NULL) xfree(tree->pred_ub);
   863       if (tree->pred_stat != NULL) xfree(tree->pred_stat);
   864 #if 0
   865       xassert(tree->cut_gen == NULL);
   866 #endif
   867       xassert(tree->mir_gen == NULL);
   868       xassert(tree->clq_gen == NULL);
   869       xfree(tree);
   870       mip->tree = NULL;
   871       return;
   872 }
   873 
   874 /***********************************************************************
   875 *  NAME
   876 *
   877 *  ios_eval_degrad - estimate obj. degrad. for down- and up-branches
   878 *
   879 *  SYNOPSIS
   880 *
   881 *  #include "glpios.h"
   882 *  void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up);
   883 *
   884 *  DESCRIPTION
   885 *
   886 *  Given optimal basis to LP relaxation of the current subproblem the
   887 *  routine ios_eval_degrad performs the dual ratio test to compute the
   888 *  objective values in the adjacent basis for down- and up-branches,
   889 *  which are stored in locations *dn and *up, assuming that x[j] is a
   890 *  variable chosen to branch upon. */
   891 
   892 void ios_eval_degrad(glp_tree *tree, int j, double *dn, double *up)
   893 {     glp_prob *mip = tree->mip;
   894       int m = mip->m, n = mip->n;
   895       int len, kase, k, t, stat;
   896       double alfa, beta, gamma, delta, dz;
   897       int *ind = tree->iwrk;
   898       double *val = tree->dwrk;
   899       /* current basis must be optimal */
   900       xassert(glp_get_status(mip) == GLP_OPT);
   901       /* basis factorization must exist */
   902       xassert(glp_bf_exists(mip));
   903       /* obtain (fractional) value of x[j] in optimal basic solution
   904          to LP relaxation of the current subproblem */
   905       xassert(1 <= j && j <= n);
   906       beta = mip->col[j]->prim;
   907       /* since the value of x[j] is fractional, it is basic; compute
   908          corresponding row of the simplex table */
   909       len = lpx_eval_tab_row(mip, m+j, ind, val);
   910       /* kase < 0 means down-branch; kase > 0 means up-branch */
   911       for (kase = -1; kase <= +1; kase += 2)
   912       {  /* for down-branch we introduce new upper bound floor(beta)
   913             for x[j]; similarly, for up-branch we introduce new lower
   914             bound ceil(beta) for x[j]; in the current basis this new
   915             upper/lower bound is violated, so in the adjacent basis
   916             x[j] will leave the basis and go to its new upper/lower
   917             bound; we need to know which non-basic variable x[k] should
   918             enter the basis to keep dual feasibility */
   919 #if 0 /* 23/XI-2009 */
   920          k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-7);
   921 #else
   922          k = lpx_dual_ratio_test(mip, len, ind, val, kase, 1e-9);
   923 #endif
   924          /* if no variable has been chosen, current basis being primal
   925             infeasible due to the new upper/lower bound of x[j] is dual
   926             unbounded, therefore, LP relaxation to corresponding branch
   927             has no primal feasible solution */
   928          if (k == 0)
   929          {  if (mip->dir == GLP_MIN)
   930             {  if (kase < 0)
   931                   *dn = +DBL_MAX;
   932                else
   933                   *up = +DBL_MAX;
   934             }
   935             else if (mip->dir == GLP_MAX)
   936             {  if (kase < 0)
   937                   *dn = -DBL_MAX;
   938                else
   939                   *up = -DBL_MAX;
   940             }
   941             else
   942                xassert(mip != mip);
   943             continue;
   944          }
   945          xassert(1 <= k && k <= m+n);
   946          /* row of the simplex table corresponding to specified basic
   947             variable x[j] is the following:
   948                x[j] = ... + alfa * x[k] + ... ;
   949             we need to know influence coefficient, alfa, at non-basic
   950             variable x[k] chosen with the dual ratio test */
   951          for (t = 1; t <= len; t++)
   952             if (ind[t] == k) break;
   953          xassert(1 <= t && t <= len);
   954          alfa = val[t];
   955          /* determine status and reduced cost of variable x[k] */
   956          if (k <= m)
   957          {  stat = mip->row[k]->stat;
   958             gamma = mip->row[k]->dual;
   959          }
   960          else
   961          {  stat = mip->col[k-m]->stat;
   962             gamma = mip->col[k-m]->dual;
   963          }
   964          /* x[k] cannot be basic or fixed non-basic */
   965          xassert(stat == GLP_NL || stat == GLP_NU || stat == GLP_NF);
   966          /* if the current basis is dual degenerative, some reduced
   967             costs, which are close to zero, may have wrong sign due to
   968             round-off errors, so correct the sign of gamma */
   969          if (mip->dir == GLP_MIN)
   970          {  if (stat == GLP_NL && gamma < 0.0 ||
   971                 stat == GLP_NU && gamma > 0.0 ||
   972                 stat == GLP_NF) gamma = 0.0;
   973          }
   974          else if (mip->dir == GLP_MAX)
   975          {  if (stat == GLP_NL && gamma > 0.0 ||
   976                 stat == GLP_NU && gamma < 0.0 ||
   977                 stat == GLP_NF) gamma = 0.0;
   978          }
   979          else
   980             xassert(mip != mip);
   981          /* determine the change of x[j] in the adjacent basis:
   982             delta x[j] = new x[j] - old x[j] */
   983          delta = (kase < 0 ? floor(beta) : ceil(beta)) - beta;
   984          /* compute the change of x[k] in the adjacent basis:
   985             delta x[k] = new x[k] - old x[k] = delta x[j] / alfa */
   986          delta /= alfa;
   987          /* compute the change of the objective in the adjacent basis:
   988             delta z = new z - old z = gamma * delta x[k] */
   989          dz = gamma * delta;
   990          if (mip->dir == GLP_MIN)
   991             xassert(dz >= 0.0);
   992          else if (mip->dir == GLP_MAX)
   993             xassert(dz <= 0.0);
   994          else
   995             xassert(mip != mip);
   996          /* compute the new objective value in the adjacent basis:
   997             new z = old z + delta z */
   998          if (kase < 0)
   999             *dn = mip->obj_val + dz;
  1000          else
  1001             *up = mip->obj_val + dz;
  1002       }
  1003       /*xprintf("obj = %g; dn = %g; up = %g\n",
  1004          mip->obj_val, *dn, *up);*/
  1005       return;
  1006 }
  1007 
  1008 /***********************************************************************
  1009 *  NAME
  1010 *
  1011 *  ios_round_bound - improve local bound by rounding
  1012 *
  1013 *  SYNOPSIS
  1014 *
  1015 *  #include "glpios.h"
  1016 *  double ios_round_bound(glp_tree *tree, double bound);
  1017 *
  1018 *  RETURNS
  1019 *
  1020 *  For the given local bound for any integer feasible solution to the
  1021 *  current subproblem the routine ios_round_bound returns an improved
  1022 *  local bound for the same integer feasible solution.
  1023 *
  1024 *  BACKGROUND
  1025 *
  1026 *  Let the current subproblem has the following objective function:
  1027 *
  1028 *     z =   sum  c[j] * x[j] + s >= b,                               (1)
  1029 *         j in J
  1030 *
  1031 *  where J = {j: c[j] is non-zero and integer, x[j] is integer}, s is
  1032 *  the sum of terms corresponding to fixed variables, b is an initial
  1033 *  local bound (minimization).
  1034 *
  1035 *  From (1) it follows that:
  1036 *
  1037 *     d *  sum  (c[j] / d) * x[j] + s >= b,                          (2)
  1038 *        j in J
  1039 *
  1040 *  or, equivalently,
  1041 *
  1042 *     sum  (c[j] / d) * x[j] >= (b - s) / d = h,                     (3)
  1043 *   j in J
  1044 *
  1045 *  where d = gcd(c[j]). Since the left-hand side of (3) is integer,
  1046 *  h = (b - s) / d can be rounded up to the nearest integer:
  1047 *
  1048 *     h' = ceil(h) = (b' - s) / d,                                   (4)
  1049 *
  1050 *  that gives an rounded, improved local bound:
  1051 *
  1052 *     b' = d * h' + s.                                               (5)
  1053 *
  1054 *  In case of maximization '>=' in (1) should be replaced by '<=' that
  1055 *  leads to the following formula:
  1056 *
  1057 *     h' = floor(h) = (b' - s) / d,                                  (6)
  1058 *
  1059 *  which should used in the same way as (4).
  1060 *
  1061 *  NOTE: If b is a valid local bound for a child of the current
  1062 *        subproblem, b' is also valid for that child subproblem. */
  1063 
  1064 double ios_round_bound(glp_tree *tree, double bound)
  1065 {     glp_prob *mip = tree->mip;
  1066       int n = mip->n;
  1067       int d, j, nn, *c = tree->iwrk;
  1068       double s, h;
  1069       /* determine c[j] and compute s */
  1070       nn = 0, s = mip->c0, d = 0;
  1071       for (j = 1; j <= n; j++)
  1072       {  GLPCOL *col = mip->col[j];
  1073          if (col->coef == 0.0) continue;
  1074          if (col->type == GLP_FX)
  1075          {  /* fixed variable */
  1076             s += col->coef * col->prim;
  1077          }
  1078          else
  1079          {  /* non-fixed variable */
  1080             if (col->kind != GLP_IV) goto skip;
  1081             if (col->coef != floor(col->coef)) goto skip;
  1082             if (fabs(col->coef) <= (double)INT_MAX)
  1083                c[++nn] = (int)fabs(col->coef);
  1084             else
  1085                d = 1;
  1086          }
  1087       }
  1088       /* compute d = gcd(c[1],...c[nn]) */
  1089       if (d == 0)
  1090       {  if (nn == 0) goto skip;
  1091          d = gcdn(nn, c);
  1092       }
  1093       xassert(d > 0);
  1094       /* compute new local bound */
  1095       if (mip->dir == GLP_MIN)
  1096       {  if (bound != +DBL_MAX)
  1097          {  h = (bound - s) / (double)d;
  1098             if (h >= floor(h) + 0.001)
  1099             {  /* round up */
  1100                h = ceil(h);
  1101                /*xprintf("d = %d; old = %g; ", d, bound);*/
  1102                bound = (double)d * h + s;
  1103                /*xprintf("new = %g\n", bound);*/
  1104             }
  1105          }
  1106       }
  1107       else if (mip->dir == GLP_MAX)
  1108       {  if (bound != -DBL_MAX)
  1109          {  h = (bound - s) / (double)d;
  1110             if (h <= ceil(h) - 0.001)
  1111             {  /* round down */
  1112                h = floor(h);
  1113                bound = (double)d * h + s;
  1114             }
  1115          }
  1116       }
  1117       else
  1118          xassert(mip != mip);
  1119 skip: return bound;
  1120 }
  1121 
  1122 /***********************************************************************
  1123 *  NAME
  1124 *
  1125 *  ios_is_hopeful - check if subproblem is hopeful
  1126 *
  1127 *  SYNOPSIS
  1128 *
  1129 *  #include "glpios.h"
  1130 *  int ios_is_hopeful(glp_tree *tree, double bound);
  1131 *
  1132 *  DESCRIPTION
  1133 *
  1134 *  Given the local bound of a subproblem the routine ios_is_hopeful
  1135 *  checks if the subproblem can have an integer optimal solution which
  1136 *  is better than the best one currently known.
  1137 *
  1138 *  RETURNS
  1139 *
  1140 *  If the subproblem can have a better integer optimal solution, the
  1141 *  routine returns non-zero; otherwise, if the corresponding branch can
  1142 *  be pruned, the routine returns zero. */
  1143 
  1144 int ios_is_hopeful(glp_tree *tree, double bound)
  1145 {     glp_prob *mip = tree->mip;
  1146       int ret = 1;
  1147       double eps;
  1148       if (mip->mip_stat == GLP_FEAS)
  1149       {  eps = tree->parm->tol_obj * (1.0 + fabs(mip->mip_obj));
  1150          switch (mip->dir)
  1151          {  case GLP_MIN:
  1152                if (bound >= mip->mip_obj - eps) ret = 0;
  1153                break;
  1154             case GLP_MAX:
  1155                if (bound <= mip->mip_obj + eps) ret = 0;
  1156                break;
  1157             default:
  1158                xassert(mip != mip);
  1159          }
  1160       }
  1161       else
  1162       {  switch (mip->dir)
  1163          {  case GLP_MIN:
  1164                if (bound == +DBL_MAX) ret = 0;
  1165                break;
  1166             case GLP_MAX:
  1167                if (bound == -DBL_MAX) ret = 0;
  1168                break;
  1169             default:
  1170                xassert(mip != mip);
  1171          }
  1172       }
  1173       return ret;
  1174 }
  1175 
  1176 /***********************************************************************
  1177 *  NAME
  1178 *
  1179 *  ios_best_node - find active node with best local bound
  1180 *
  1181 *  SYNOPSIS
  1182 *
  1183 *  #include "glpios.h"
  1184 *  int ios_best_node(glp_tree *tree);
  1185 *
  1186 *  DESCRIPTION
  1187 *
  1188 *  The routine ios_best_node finds an active node whose local bound is
  1189 *  best among other active nodes.
  1190 *
  1191 *  It is understood that the integer optimal solution of the original
  1192 *  mip problem cannot be better than the best bound, so the best bound
  1193 *  is an lower (minimization) or upper (maximization) global bound for
  1194 *  the original problem.
  1195 *
  1196 *  RETURNS
  1197 *
  1198 *  The routine ios_best_node returns the subproblem reference number
  1199 *  for the best node. However, if the tree is empty, it returns zero. */
  1200 
  1201 int ios_best_node(glp_tree *tree)
  1202 {     IOSNPD *node, *best = NULL;
  1203       switch (tree->mip->dir)
  1204       {  case GLP_MIN:
  1205             /* minimization */
  1206             for (node = tree->head; node != NULL; node = node->next)
  1207                if (best == NULL || best->bound > node->bound)
  1208                   best = node;
  1209             break;
  1210          case GLP_MAX:
  1211             /* maximization */
  1212             for (node = tree->head; node != NULL; node = node->next)
  1213                if (best == NULL || best->bound < node->bound)
  1214                   best = node;
  1215             break;
  1216          default:
  1217             xassert(tree != tree);
  1218       }
  1219       return best == NULL ? 0 : best->p;
  1220 }
  1221 
  1222 /***********************************************************************
  1223 *  NAME
  1224 *
  1225 *  ios_relative_gap - compute relative mip gap
  1226 *
  1227 *  SYNOPSIS
  1228 *
  1229 *  #include "glpios.h"
  1230 *  double ios_relative_gap(glp_tree *tree);
  1231 *
  1232 *  DESCRIPTION
  1233 *
  1234 *  The routine ios_relative_gap computes the relative mip gap using the
  1235 *  formula:
  1236 *
  1237 *     gap = |best_mip - best_bnd| / (|best_mip| + DBL_EPSILON),
  1238 *
  1239 *  where best_mip is the best integer feasible solution found so far,
  1240 *  best_bnd is the best (global) bound. If no integer feasible solution
  1241 *  has been found yet, rel_gap is set to DBL_MAX.
  1242 *
  1243 *  RETURNS
  1244 *
  1245 *  The routine ios_relative_gap returns the relative mip gap. */
  1246 
  1247 double ios_relative_gap(glp_tree *tree)
  1248 {     glp_prob *mip = tree->mip;
  1249       int p;
  1250       double best_mip, best_bnd, gap;
  1251       if (mip->mip_stat == GLP_FEAS)
  1252       {  best_mip = mip->mip_obj;
  1253          p = ios_best_node(tree);
  1254          if (p == 0)
  1255          {  /* the tree is empty */
  1256             gap = 0.0;
  1257          }
  1258          else
  1259          {  best_bnd = tree->slot[p].node->bound;
  1260             gap = fabs(best_mip - best_bnd) / (fabs(best_mip) +
  1261                DBL_EPSILON);
  1262          }
  1263       }
  1264       else
  1265       {  /* no integer feasible solution has been found yet */
  1266          gap = DBL_MAX;
  1267       }
  1268       return gap;
  1269 }
  1270 
  1271 /***********************************************************************
  1272 *  NAME
  1273 *
  1274 *  ios_solve_node - solve LP relaxation of current subproblem
  1275 *
  1276 *  SYNOPSIS
  1277 *
  1278 *  #include "glpios.h"
  1279 *  int ios_solve_node(glp_tree *tree);
  1280 *
  1281 *  DESCRIPTION
  1282 *
  1283 *  The routine ios_solve_node re-optimizes LP relaxation of the current
  1284 *  subproblem using the dual simplex method.
  1285 *
  1286 *  RETURNS
  1287 *
  1288 *  The routine returns the code which is reported by glp_simplex. */
  1289 
  1290 int ios_solve_node(glp_tree *tree)
  1291 {     glp_prob *mip = tree->mip;
  1292       glp_smcp parm;
  1293       int ret;
  1294       /* the current subproblem must exist */
  1295       xassert(tree->curr != NULL);
  1296       /* set some control parameters */
  1297       glp_init_smcp(&parm);
  1298       switch (tree->parm->msg_lev)
  1299       {  case GLP_MSG_OFF:
  1300             parm.msg_lev = GLP_MSG_OFF; break;
  1301          case GLP_MSG_ERR:
  1302             parm.msg_lev = GLP_MSG_ERR; break;
  1303          case GLP_MSG_ON:
  1304          case GLP_MSG_ALL:
  1305             parm.msg_lev = GLP_MSG_ON; break;
  1306          case GLP_MSG_DBG:
  1307             parm.msg_lev = GLP_MSG_ALL; break;
  1308          default:
  1309             xassert(tree != tree);
  1310       }
  1311       parm.meth = GLP_DUALP;
  1312       if (tree->parm->msg_lev < GLP_MSG_DBG)
  1313          parm.out_dly = tree->parm->out_dly;
  1314       else
  1315          parm.out_dly = 0;
  1316       /* if the incumbent objective value is already known, use it to
  1317          prematurely terminate the dual simplex search */
  1318       if (mip->mip_stat == GLP_FEAS)
  1319       {  switch (tree->mip->dir)
  1320          {  case GLP_MIN:
  1321                parm.obj_ul = mip->mip_obj;
  1322                break;
  1323             case GLP_MAX:
  1324                parm.obj_ll = mip->mip_obj;
  1325                break;
  1326             default:
  1327                xassert(mip != mip);
  1328          }
  1329       }
  1330       /* try to solve/re-optimize the LP relaxation */
  1331       ret = glp_simplex(mip, &parm);
  1332       tree->curr->solved++;
  1333 #if 0
  1334       xprintf("ret = %d; status = %d; pbs = %d; dbs = %d; some = %d\n",
  1335          ret, glp_get_status(mip), mip->pbs_stat, mip->dbs_stat,
  1336          mip->some);
  1337       lpx_print_sol(mip, "sol");
  1338 #endif
  1339       return ret;
  1340 }
  1341 
  1342 /**********************************************************************/
  1343 
  1344 IOSPOOL *ios_create_pool(glp_tree *tree)
  1345 {     /* create cut pool */
  1346       IOSPOOL *pool;
  1347 #if 0
  1348       pool = dmp_get_atom(tree->pool, sizeof(IOSPOOL));
  1349 #else
  1350       xassert(tree == tree);
  1351       pool = xmalloc(sizeof(IOSPOOL));
  1352 #endif
  1353       pool->size = 0;
  1354       pool->head = pool->tail = NULL;
  1355       pool->ord = 0, pool->curr = NULL;
  1356       return pool;
  1357 }
  1358 
  1359 int ios_add_row(glp_tree *tree, IOSPOOL *pool,
  1360       const char *name, int klass, int flags, int len, const int ind[],
  1361       const double val[], int type, double rhs)
  1362 {     /* add row (constraint) to the cut pool */
  1363       IOSCUT *cut;
  1364       IOSAIJ *aij;
  1365       int k;
  1366       xassert(pool != NULL);
  1367       cut = dmp_get_atom(tree->pool, sizeof(IOSCUT));
  1368       if (name == NULL || name[0] == '\0')
  1369          cut->name = NULL;
  1370       else
  1371       {  for (k = 0; name[k] != '\0'; k++)
  1372          {  if (k == 256)
  1373                xerror("glp_ios_add_row: cut name too long\n");
  1374             if (iscntrl((unsigned char)name[k]))
  1375                xerror("glp_ios_add_row: cut name contains invalid chara"
  1376                   "cter(s)\n");
  1377          }
  1378          cut->name = dmp_get_atom(tree->pool, strlen(name)+1);
  1379          strcpy(cut->name, name);
  1380       }
  1381       if (!(0 <= klass && klass <= 255))
  1382          xerror("glp_ios_add_row: klass = %d; invalid cut class\n",
  1383             klass);
  1384       cut->klass = (unsigned char)klass;
  1385       if (flags != 0)
  1386          xerror("glp_ios_add_row: flags = %d; invalid cut flags\n",
  1387             flags);
  1388       cut->ptr = NULL;
  1389       if (!(0 <= len && len <= tree->n))
  1390          xerror("glp_ios_add_row: len = %d; invalid cut length\n",
  1391             len);
  1392       for (k = 1; k <= len; k++)
  1393       {  aij = dmp_get_atom(tree->pool, sizeof(IOSAIJ));
  1394          if (!(1 <= ind[k] && ind[k] <= tree->n))
  1395             xerror("glp_ios_add_row: ind[%d] = %d; column index out of "
  1396                "range\n", k, ind[k]);
  1397          aij->j = ind[k];
  1398          aij->val = val[k];
  1399          aij->next = cut->ptr;
  1400          cut->ptr = aij;
  1401       }
  1402       if (!(type == GLP_LO || type == GLP_UP || type == GLP_FX))
  1403          xerror("glp_ios_add_row: type = %d; invalid cut type\n",
  1404             type);
  1405       cut->type = (unsigned char)type;
  1406       cut->rhs = rhs;
  1407       cut->prev = pool->tail;
  1408       cut->next = NULL;
  1409       if (cut->prev == NULL)
  1410          pool->head = cut;
  1411       else
  1412          cut->prev->next = cut;
  1413       pool->tail = cut;
  1414       pool->size++;
  1415       return pool->size;
  1416 }
  1417 
  1418 IOSCUT *ios_find_row(IOSPOOL *pool, int i)
  1419 {     /* find row (constraint) in the cut pool */
  1420       /* (smart linear search) */
  1421       xassert(pool != NULL);
  1422       xassert(1 <= i && i <= pool->size);
  1423       if (pool->ord == 0)
  1424       {  xassert(pool->curr == NULL);
  1425          pool->ord = 1;
  1426          pool->curr = pool->head;
  1427       }
  1428       xassert(pool->curr != NULL);
  1429       if (i < pool->ord)
  1430       {  if (i < pool->ord - i)
  1431          {  pool->ord = 1;
  1432             pool->curr = pool->head;
  1433             while (pool->ord != i)
  1434             {  pool->ord++;
  1435                xassert(pool->curr != NULL);
  1436                pool->curr = pool->curr->next;
  1437             }
  1438          }
  1439          else
  1440          {  while (pool->ord != i)
  1441             {  pool->ord--;
  1442                xassert(pool->curr != NULL);
  1443                pool->curr = pool->curr->prev;
  1444             }
  1445          }
  1446       }
  1447       else if (i > pool->ord)
  1448       {  if (i - pool->ord < pool->size - i)
  1449          {  while (pool->ord != i)
  1450             {  pool->ord++;
  1451                xassert(pool->curr != NULL);
  1452                pool->curr = pool->curr->next;
  1453             }
  1454          }
  1455          else
  1456          {  pool->ord = pool->size;
  1457             pool->curr = pool->tail;
  1458             while (pool->ord != i)
  1459             {  pool->ord--;
  1460                xassert(pool->curr != NULL);
  1461                pool->curr = pool->curr->prev;
  1462             }
  1463          }
  1464       }
  1465       xassert(pool->ord == i);
  1466       xassert(pool->curr != NULL);
  1467       return pool->curr;
  1468 }
  1469 
  1470 void ios_del_row(glp_tree *tree, IOSPOOL *pool, int i)
  1471 {     /* remove row (constraint) from the cut pool */
  1472       IOSCUT *cut;
  1473       IOSAIJ *aij;
  1474       xassert(pool != NULL);
  1475       if (!(1 <= i && i <= pool->size))
  1476          xerror("glp_ios_del_row: i = %d; cut number out of range\n",
  1477             i);
  1478       cut = ios_find_row(pool, i);
  1479       xassert(pool->curr == cut);
  1480       if (cut->next != NULL)
  1481          pool->curr = cut->next;
  1482       else if (cut->prev != NULL)
  1483          pool->ord--, pool->curr = cut->prev;
  1484       else
  1485          pool->ord = 0, pool->curr = NULL;
  1486       if (cut->name != NULL)
  1487          dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
  1488       if (cut->prev == NULL)
  1489       {  xassert(pool->head == cut);
  1490          pool->head = cut->next;
  1491       }
  1492       else
  1493       {  xassert(cut->prev->next == cut);
  1494          cut->prev->next = cut->next;
  1495       }
  1496       if (cut->next == NULL)
  1497       {  xassert(pool->tail == cut);
  1498          pool->tail = cut->prev;
  1499       }
  1500       else
  1501       {  xassert(cut->next->prev == cut);
  1502          cut->next->prev = cut->prev;
  1503       }
  1504       while (cut->ptr != NULL)
  1505       {  aij = cut->ptr;
  1506          cut->ptr = aij->next;
  1507          dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
  1508       }
  1509       dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
  1510       pool->size--;
  1511       return;
  1512 }
  1513 
  1514 void ios_clear_pool(glp_tree *tree, IOSPOOL *pool)
  1515 {     /* remove all rows (constraints) from the cut pool */
  1516       xassert(pool != NULL);
  1517       while (pool->head != NULL)
  1518       {  IOSCUT *cut = pool->head;
  1519          pool->head = cut->next;
  1520          if (cut->name != NULL)
  1521             dmp_free_atom(tree->pool, cut->name, strlen(cut->name)+1);
  1522          while (cut->ptr != NULL)
  1523          {  IOSAIJ *aij = cut->ptr;
  1524             cut->ptr = aij->next;
  1525             dmp_free_atom(tree->pool, aij, sizeof(IOSAIJ));
  1526          }
  1527          dmp_free_atom(tree->pool, cut, sizeof(IOSCUT));
  1528       }
  1529       pool->size = 0;
  1530       pool->head = pool->tail = NULL;
  1531       pool->ord = 0, pool->curr = NULL;
  1532       return;
  1533 }
  1534 
  1535 void ios_delete_pool(glp_tree *tree, IOSPOOL *pool)
  1536 {     /* delete cut pool */
  1537       xassert(pool != NULL);
  1538       ios_clear_pool(tree, pool);
  1539       xfree(pool);
  1540       return;
  1541 }
  1542 
  1543 /**********************************************************************/
  1544 
  1545 #if 0
  1546 static int refer_to_node(glp_tree *tree, int j)
  1547 {     /* determine node number corresponding to binary variable x[j] or
  1548          its complement */
  1549       glp_prob *mip = tree->mip;
  1550       int n = mip->n;
  1551       int *ref;
  1552       if (j > 0)
  1553          ref = tree->n_ref;
  1554       else
  1555          ref = tree->c_ref, j = - j;
  1556       xassert(1 <= j && j <= n);
  1557       if (ref[j] == 0)
  1558       {  /* new node is needed */
  1559          SCG *g = tree->g;
  1560          int n_max = g->n_max;
  1561          ref[j] = scg_add_nodes(g, 1);
  1562          if (g->n_max > n_max)
  1563          {  int *save = tree->j_ref;
  1564             tree->j_ref = xcalloc(1+g->n_max, sizeof(int));
  1565             memcpy(&tree->j_ref[1], &save[1], g->n * sizeof(int));
  1566             xfree(save);
  1567          }
  1568          xassert(ref[j] == g->n);
  1569          tree->j_ref[ref[j]] = j;
  1570          xassert(tree->curr != NULL);
  1571          if (tree->curr->level > 0) tree->curr->own_nn++;
  1572       }
  1573       return ref[j];
  1574 }
  1575 #endif
  1576 
  1577 #if 0
  1578 void ios_add_edge(glp_tree *tree, int j1, int j2)
  1579 {     /* add new edge to the conflict graph */
  1580       glp_prob *mip = tree->mip;
  1581       int n = mip->n;
  1582       SCGRIB *e;
  1583       int first, i1, i2;
  1584       xassert(-n <= j1 && j1 <= +n && j1 != 0);
  1585       xassert(-n <= j2 && j2 <= +n && j2 != 0);
  1586       xassert(j1 != j2);
  1587       /* determine number of the first node, which was added for the
  1588          current subproblem */
  1589       xassert(tree->curr != NULL);
  1590       first = tree->g->n - tree->curr->own_nn + 1;
  1591       /* determine node numbers for both endpoints */
  1592       i1 = refer_to_node(tree, j1);
  1593       i2 = refer_to_node(tree, j2);
  1594       /* add edge (i1,i2) to the conflict graph */
  1595       e = scg_add_edge(tree->g, i1, i2);
  1596       /* if the current subproblem is not the root and both endpoints
  1597          were created on some previous levels, save the edge */
  1598       if (tree->curr->level > 0 && i1 < first && i2 < first)
  1599       {  IOSRIB *rib;
  1600          rib = dmp_get_atom(tree->pool, sizeof(IOSRIB));
  1601          rib->j1 = j1;
  1602          rib->j2 = j2;
  1603          rib->e = e;
  1604          rib->next = tree->curr->e_ptr;
  1605          tree->curr->e_ptr = rib;
  1606       }
  1607       return;
  1608 }
  1609 #endif
  1610 
  1611 /* eof */