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

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