src/glpapi01.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
/* glpapi01.c (problem creating and modifying routines) */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpios.h"
alpar@1
    26
alpar@1
    27
/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */
alpar@1
    28
alpar@1
    29
#define M_MAX 100000000 /* = 100*10^6 */
alpar@1
    30
/* maximal number of rows in the problem object */
alpar@1
    31
alpar@1
    32
#define N_MAX 100000000 /* = 100*10^6 */
alpar@1
    33
/* maximal number of columns in the problem object */
alpar@1
    34
alpar@1
    35
#define NNZ_MAX 500000000 /* = 500*10^6 */
alpar@1
    36
/* maximal number of constraint coefficients in the problem object */
alpar@1
    37
alpar@1
    38
/***********************************************************************
alpar@1
    39
*  NAME
alpar@1
    40
*
alpar@1
    41
*  glp_create_prob - create problem object
alpar@1
    42
*
alpar@1
    43
*  SYNOPSIS
alpar@1
    44
*
alpar@1
    45
*  glp_prob *glp_create_prob(void);
alpar@1
    46
*
alpar@1
    47
*  DESCRIPTION
alpar@1
    48
*
alpar@1
    49
*  The routine glp_create_prob creates a new problem object, which is
alpar@1
    50
*  initially "empty", i.e. has no rows and columns.
alpar@1
    51
*
alpar@1
    52
*  RETURNS
alpar@1
    53
*
alpar@1
    54
*  The routine returns a pointer to the object created, which should be
alpar@1
    55
*  used in any subsequent operations on this object. */
alpar@1
    56
alpar@1
    57
static void create_prob(glp_prob *lp)
alpar@1
    58
{     lp->magic = GLP_PROB_MAGIC;
alpar@1
    59
      lp->pool = dmp_create_pool();
alpar@1
    60
#if 0 /* 17/XI-2009 */
alpar@1
    61
      lp->cps = xmalloc(sizeof(struct LPXCPS));
alpar@1
    62
      lpx_reset_parms(lp);
alpar@1
    63
#else
alpar@1
    64
      lp->parms = NULL;
alpar@1
    65
#endif
alpar@1
    66
      lp->tree = NULL;
alpar@1
    67
#if 0
alpar@1
    68
      lp->lwa = 0;
alpar@1
    69
      lp->cwa = NULL;
alpar@1
    70
#endif
alpar@1
    71
      /* LP/MIP data */
alpar@1
    72
      lp->name = NULL;
alpar@1
    73
      lp->obj = NULL;
alpar@1
    74
      lp->dir = GLP_MIN;
alpar@1
    75
      lp->c0 = 0.0;
alpar@1
    76
      lp->m_max = 100;
alpar@1
    77
      lp->n_max = 200;
alpar@1
    78
      lp->m = lp->n = 0;
alpar@1
    79
      lp->nnz = 0;
alpar@1
    80
      lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
alpar@1
    81
      lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
alpar@1
    82
      lp->r_tree = lp->c_tree = NULL;
alpar@1
    83
      /* basis factorization */
alpar@1
    84
      lp->valid = 0;
alpar@1
    85
      lp->head = xcalloc(1+lp->m_max, sizeof(int));
alpar@1
    86
      lp->bfcp = NULL;
alpar@1
    87
      lp->bfd = NULL;
alpar@1
    88
      /* basic solution (LP) */
alpar@1
    89
      lp->pbs_stat = lp->dbs_stat = GLP_UNDEF;
alpar@1
    90
      lp->obj_val = 0.0;
alpar@1
    91
      lp->it_cnt = 0;
alpar@1
    92
      lp->some = 0;
alpar@1
    93
      /* interior-point solution (LP) */
alpar@1
    94
      lp->ipt_stat = GLP_UNDEF;
alpar@1
    95
      lp->ipt_obj = 0.0;
alpar@1
    96
      /* integer solution (MIP) */
alpar@1
    97
      lp->mip_stat = GLP_UNDEF;
alpar@1
    98
      lp->mip_obj = 0.0;
alpar@1
    99
      return;
alpar@1
   100
}
alpar@1
   101
alpar@1
   102
glp_prob *glp_create_prob(void)
alpar@1
   103
{     glp_prob *lp;
alpar@1
   104
      lp = xmalloc(sizeof(glp_prob));
alpar@1
   105
      create_prob(lp);
alpar@1
   106
      return lp;
alpar@1
   107
}
alpar@1
   108
alpar@1
   109
/***********************************************************************
alpar@1
   110
*  NAME
alpar@1
   111
*
alpar@1
   112
*  glp_set_prob_name - assign (change) problem name
alpar@1
   113
*
alpar@1
   114
*  SYNOPSIS
alpar@1
   115
*
alpar@1
   116
*  void glp_set_prob_name(glp_prob *lp, const char *name);
alpar@1
   117
*
alpar@1
   118
*  DESCRIPTION
alpar@1
   119
*
alpar@1
   120
*  The routine glp_set_prob_name assigns a given symbolic name (1 up to
alpar@1
   121
*  255 characters) to the specified problem object.
alpar@1
   122
*
alpar@1
   123
*  If the parameter name is NULL or empty string, the routine erases an
alpar@1
   124
*  existing symbolic name of the problem object. */
alpar@1
   125
alpar@1
   126
void glp_set_prob_name(glp_prob *lp, const char *name)
alpar@1
   127
{     glp_tree *tree = lp->tree;
alpar@1
   128
      if (tree != NULL && tree->reason != 0)
alpar@1
   129
         xerror("glp_set_prob_name: operation not allowed\n");
alpar@1
   130
      if (lp->name != NULL)
alpar@1
   131
      {  dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1);
alpar@1
   132
         lp->name = NULL;
alpar@1
   133
      }
alpar@1
   134
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   135
      {  int k;
alpar@1
   136
         for (k = 0; name[k] != '\0'; k++)
alpar@1
   137
         {  if (k == 256)
alpar@1
   138
               xerror("glp_set_prob_name: problem name too long\n");
alpar@1
   139
            if (iscntrl((unsigned char)name[k]))
alpar@1
   140
               xerror("glp_set_prob_name: problem name contains invalid"
alpar@1
   141
                  " character(s)\n");
alpar@1
   142
         }
alpar@1
   143
         lp->name = dmp_get_atom(lp->pool, strlen(name)+1);
alpar@1
   144
         strcpy(lp->name, name);
alpar@1
   145
      }
alpar@1
   146
      return;
alpar@1
   147
}
alpar@1
   148
alpar@1
   149
/***********************************************************************
alpar@1
   150
*  NAME
alpar@1
   151
*
alpar@1
   152
*  glp_set_obj_name - assign (change) objective function name
alpar@1
   153
*
alpar@1
   154
*  SYNOPSIS
alpar@1
   155
*
alpar@1
   156
*  void glp_set_obj_name(glp_prob *lp, const char *name);
alpar@1
   157
*
alpar@1
   158
*  DESCRIPTION
alpar@1
   159
*
alpar@1
   160
*  The routine glp_set_obj_name assigns a given symbolic name (1 up to
alpar@1
   161
*  255 characters) to the objective function of the specified problem
alpar@1
   162
*  object.
alpar@1
   163
*
alpar@1
   164
*  If the parameter name is NULL or empty string, the routine erases an
alpar@1
   165
*  existing name of the objective function. */
alpar@1
   166
alpar@1
   167
void glp_set_obj_name(glp_prob *lp, const char *name)
alpar@1
   168
{     glp_tree *tree = lp->tree;
alpar@1
   169
      if (tree != NULL && tree->reason != 0)
alpar@1
   170
         xerror("glp_set_obj_name: operation not allowed\n");
alpar@1
   171
     if (lp->obj != NULL)
alpar@1
   172
      {  dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1);
alpar@1
   173
         lp->obj = NULL;
alpar@1
   174
      }
alpar@1
   175
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   176
      {  int k;
alpar@1
   177
         for (k = 0; name[k] != '\0'; k++)
alpar@1
   178
         {  if (k == 256)
alpar@1
   179
               xerror("glp_set_obj_name: objective name too long\n");
alpar@1
   180
            if (iscntrl((unsigned char)name[k]))
alpar@1
   181
               xerror("glp_set_obj_name: objective name contains invali"
alpar@1
   182
                  "d character(s)\n");
alpar@1
   183
         }
alpar@1
   184
         lp->obj = dmp_get_atom(lp->pool, strlen(name)+1);
alpar@1
   185
         strcpy(lp->obj, name);
alpar@1
   186
      }
alpar@1
   187
      return;
alpar@1
   188
}
alpar@1
   189
alpar@1
   190
/***********************************************************************
alpar@1
   191
*  NAME
alpar@1
   192
*
alpar@1
   193
*  glp_set_obj_dir - set (change) optimization direction flag
alpar@1
   194
*
alpar@1
   195
*  SYNOPSIS
alpar@1
   196
*
alpar@1
   197
*  void glp_set_obj_dir(glp_prob *lp, int dir);
alpar@1
   198
*
alpar@1
   199
*  DESCRIPTION
alpar@1
   200
*
alpar@1
   201
*  The routine glp_set_obj_dir sets (changes) optimization direction
alpar@1
   202
*  flag (i.e. "sense" of the objective function) as specified by the
alpar@1
   203
*  parameter dir:
alpar@1
   204
*
alpar@1
   205
*  GLP_MIN - minimization;
alpar@1
   206
*  GLP_MAX - maximization. */
alpar@1
   207
alpar@1
   208
void glp_set_obj_dir(glp_prob *lp, int dir)
alpar@1
   209
{     glp_tree *tree = lp->tree;
alpar@1
   210
      if (tree != NULL && tree->reason != 0)
alpar@1
   211
         xerror("glp_set_obj_dir: operation not allowed\n");
alpar@1
   212
     if (!(dir == GLP_MIN || dir == GLP_MAX))
alpar@1
   213
         xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n",
alpar@1
   214
            dir);
alpar@1
   215
      lp->dir = dir;
alpar@1
   216
      return;
alpar@1
   217
}
alpar@1
   218
alpar@1
   219
/***********************************************************************
alpar@1
   220
*  NAME
alpar@1
   221
*
alpar@1
   222
*  glp_add_rows - add new rows to problem object
alpar@1
   223
*
alpar@1
   224
*  SYNOPSIS
alpar@1
   225
*
alpar@1
   226
*  int glp_add_rows(glp_prob *lp, int nrs);
alpar@1
   227
*
alpar@1
   228
*  DESCRIPTION
alpar@1
   229
*
alpar@1
   230
*  The routine glp_add_rows adds nrs rows (constraints) to the specified
alpar@1
   231
*  problem object. New rows are always added to the end of the row list,
alpar@1
   232
*  so the ordinal numbers of existing rows remain unchanged.
alpar@1
   233
*
alpar@1
   234
*  Being added each new row is initially free (unbounded) and has empty
alpar@1
   235
*  list of the constraint coefficients.
alpar@1
   236
*
alpar@1
   237
*  RETURNS
alpar@1
   238
*
alpar@1
   239
*  The routine glp_add_rows returns the ordinal number of the first new
alpar@1
   240
*  row added to the problem object. */
alpar@1
   241
alpar@1
   242
int glp_add_rows(glp_prob *lp, int nrs)
alpar@1
   243
{     glp_tree *tree = lp->tree;
alpar@1
   244
      GLPROW *row;
alpar@1
   245
      int m_new, i;
alpar@1
   246
      /* determine new number of rows */
alpar@1
   247
      if (nrs < 1)
alpar@1
   248
         xerror("glp_add_rows: nrs = %d; invalid number of rows\n",
alpar@1
   249
            nrs);
alpar@1
   250
      if (nrs > M_MAX - lp->m)
alpar@1
   251
         xerror("glp_add_rows: nrs = %d; too many rows\n", nrs);
alpar@1
   252
      m_new = lp->m + nrs;
alpar@1
   253
      /* increase the room, if necessary */
alpar@1
   254
      if (lp->m_max < m_new)
alpar@1
   255
      {  GLPROW **save = lp->row;
alpar@1
   256
         while (lp->m_max < m_new)
alpar@1
   257
         {  lp->m_max += lp->m_max;
alpar@1
   258
            xassert(lp->m_max > 0);
alpar@1
   259
         }
alpar@1
   260
         lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *));
alpar@1
   261
         memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *));
alpar@1
   262
         xfree(save);
alpar@1
   263
         /* do not forget about the basis header */
alpar@1
   264
         xfree(lp->head);
alpar@1
   265
         lp->head = xcalloc(1+lp->m_max, sizeof(int));
alpar@1
   266
      }
alpar@1
   267
      /* add new rows to the end of the row list */
alpar@1
   268
      for (i = lp->m+1; i <= m_new; i++)
alpar@1
   269
      {  /* create row descriptor */
alpar@1
   270
         lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW));
alpar@1
   271
         row->i = i;
alpar@1
   272
         row->name = NULL;
alpar@1
   273
         row->node = NULL;
alpar@1
   274
#if 1 /* 20/IX-2008 */
alpar@1
   275
         row->level = 0;
alpar@1
   276
         row->origin = 0;
alpar@1
   277
         row->klass = 0;
alpar@1
   278
         if (tree != NULL)
alpar@1
   279
         {  switch (tree->reason)
alpar@1
   280
            {  case 0:
alpar@1
   281
                  break;
alpar@1
   282
               case GLP_IROWGEN:
alpar@1
   283
                  xassert(tree->curr != NULL);
alpar@1
   284
                  row->level = tree->curr->level;
alpar@1
   285
                  row->origin = GLP_RF_LAZY;
alpar@1
   286
                  break;
alpar@1
   287
               case GLP_ICUTGEN:
alpar@1
   288
                  xassert(tree->curr != NULL);
alpar@1
   289
                  row->level = tree->curr->level;
alpar@1
   290
                  row->origin = GLP_RF_CUT;
alpar@1
   291
                  break;
alpar@1
   292
               default:
alpar@1
   293
                  xassert(tree != tree);
alpar@1
   294
            }
alpar@1
   295
         }
alpar@1
   296
#endif
alpar@1
   297
         row->type = GLP_FR;
alpar@1
   298
         row->lb = row->ub = 0.0;
alpar@1
   299
         row->ptr = NULL;
alpar@1
   300
         row->rii = 1.0;
alpar@1
   301
         row->stat = GLP_BS;
alpar@1
   302
#if 0
alpar@1
   303
         row->bind = -1;
alpar@1
   304
#else
alpar@1
   305
         row->bind = 0;
alpar@1
   306
#endif
alpar@1
   307
         row->prim = row->dual = 0.0;
alpar@1
   308
         row->pval = row->dval = 0.0;
alpar@1
   309
         row->mipx = 0.0;
alpar@1
   310
      }
alpar@1
   311
      /* set new number of rows */
alpar@1
   312
      lp->m = m_new;
alpar@1
   313
      /* invalidate the basis factorization */
alpar@1
   314
      lp->valid = 0;
alpar@1
   315
#if 1
alpar@1
   316
      if (tree != NULL && tree->reason != 0) tree->reopt = 1;
alpar@1
   317
#endif
alpar@1
   318
      /* return the ordinal number of the first row added */
alpar@1
   319
      return m_new - nrs + 1;
alpar@1
   320
}
alpar@1
   321
alpar@1
   322
/***********************************************************************
alpar@1
   323
*  NAME
alpar@1
   324
*
alpar@1
   325
*  glp_add_cols - add new columns to problem object
alpar@1
   326
*
alpar@1
   327
*  SYNOPSIS
alpar@1
   328
*
alpar@1
   329
*  int glp_add_cols(glp_prob *lp, int ncs);
alpar@1
   330
*
alpar@1
   331
*  DESCRIPTION
alpar@1
   332
*
alpar@1
   333
*  The routine glp_add_cols adds ncs columns (structural variables) to
alpar@1
   334
*  the specified problem object. New columns are always added to the end
alpar@1
   335
*  of the column list, so the ordinal numbers of existing columns remain
alpar@1
   336
*  unchanged.
alpar@1
   337
*
alpar@1
   338
*  Being added each new column is initially fixed at zero and has empty
alpar@1
   339
*  list of the constraint coefficients.
alpar@1
   340
*
alpar@1
   341
*  RETURNS
alpar@1
   342
*
alpar@1
   343
*  The routine glp_add_cols returns the ordinal number of the first new
alpar@1
   344
*  column added to the problem object. */
alpar@1
   345
alpar@1
   346
int glp_add_cols(glp_prob *lp, int ncs)
alpar@1
   347
{     glp_tree *tree = lp->tree;
alpar@1
   348
      GLPCOL *col;
alpar@1
   349
      int n_new, j;
alpar@1
   350
      if (tree != NULL && tree->reason != 0)
alpar@1
   351
         xerror("glp_add_cols: operation not allowed\n");
alpar@1
   352
      /* determine new number of columns */
alpar@1
   353
      if (ncs < 1)
alpar@1
   354
         xerror("glp_add_cols: ncs = %d; invalid number of columns\n",
alpar@1
   355
            ncs);
alpar@1
   356
      if (ncs > N_MAX - lp->n)
alpar@1
   357
         xerror("glp_add_cols: ncs = %d; too many columns\n", ncs);
alpar@1
   358
      n_new = lp->n + ncs;
alpar@1
   359
      /* increase the room, if necessary */
alpar@1
   360
      if (lp->n_max < n_new)
alpar@1
   361
      {  GLPCOL **save = lp->col;
alpar@1
   362
         while (lp->n_max < n_new)
alpar@1
   363
         {  lp->n_max += lp->n_max;
alpar@1
   364
            xassert(lp->n_max > 0);
alpar@1
   365
         }
alpar@1
   366
         lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *));
alpar@1
   367
         memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *));
alpar@1
   368
         xfree(save);
alpar@1
   369
      }
alpar@1
   370
      /* add new columns to the end of the column list */
alpar@1
   371
      for (j = lp->n+1; j <= n_new; j++)
alpar@1
   372
      {  /* create column descriptor */
alpar@1
   373
         lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL));
alpar@1
   374
         col->j = j;
alpar@1
   375
         col->name = NULL;
alpar@1
   376
         col->node = NULL;
alpar@1
   377
         col->kind = GLP_CV;
alpar@1
   378
         col->type = GLP_FX;
alpar@1
   379
         col->lb = col->ub = 0.0;
alpar@1
   380
         col->coef = 0.0;
alpar@1
   381
         col->ptr = NULL;
alpar@1
   382
         col->sjj = 1.0;
alpar@1
   383
         col->stat = GLP_NS;
alpar@1
   384
#if 0
alpar@1
   385
         col->bind = -1;
alpar@1
   386
#else
alpar@1
   387
         col->bind = 0; /* the basis may remain valid */
alpar@1
   388
#endif
alpar@1
   389
         col->prim = col->dual = 0.0;
alpar@1
   390
         col->pval = col->dval = 0.0;
alpar@1
   391
         col->mipx = 0.0;
alpar@1
   392
      }
alpar@1
   393
      /* set new number of columns */
alpar@1
   394
      lp->n = n_new;
alpar@1
   395
      /* return the ordinal number of the first column added */
alpar@1
   396
      return n_new - ncs + 1;
alpar@1
   397
}
alpar@1
   398
alpar@1
   399
/***********************************************************************
alpar@1
   400
*  NAME
alpar@1
   401
*
alpar@1
   402
*  glp_set_row_name - assign (change) row name
alpar@1
   403
*
alpar@1
   404
*  SYNOPSIS
alpar@1
   405
*
alpar@1
   406
*  void glp_set_row_name(glp_prob *lp, int i, const char *name);
alpar@1
   407
*
alpar@1
   408
*  DESCRIPTION
alpar@1
   409
*
alpar@1
   410
*  The routine glp_set_row_name assigns a given symbolic name (1 up to
alpar@1
   411
*  255 characters) to i-th row (auxiliary variable) of the specified
alpar@1
   412
*  problem object.
alpar@1
   413
*
alpar@1
   414
*  If the parameter name is NULL or empty string, the routine erases an
alpar@1
   415
*  existing name of i-th row. */
alpar@1
   416
alpar@1
   417
void glp_set_row_name(glp_prob *lp, int i, const char *name)
alpar@1
   418
{     glp_tree *tree = lp->tree;
alpar@1
   419
      GLPROW *row;
alpar@1
   420
      if (!(1 <= i && i <= lp->m))
alpar@1
   421
         xerror("glp_set_row_name: i = %d; row number out of range\n",
alpar@1
   422
            i);
alpar@1
   423
      row = lp->row[i];
alpar@1
   424
      if (tree != NULL && tree->reason != 0)
alpar@1
   425
      {  xassert(tree->curr != NULL);
alpar@1
   426
         xassert(row->level == tree->curr->level);
alpar@1
   427
      }
alpar@1
   428
      if (row->name != NULL)
alpar@1
   429
      {  if (row->node != NULL)
alpar@1
   430
         {  xassert(lp->r_tree != NULL);
alpar@1
   431
            avl_delete_node(lp->r_tree, row->node);
alpar@1
   432
            row->node = NULL;
alpar@1
   433
         }
alpar@1
   434
         dmp_free_atom(lp->pool, row->name, strlen(row->name)+1);
alpar@1
   435
         row->name = NULL;
alpar@1
   436
      }
alpar@1
   437
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   438
      {  int k;
alpar@1
   439
         for (k = 0; name[k] != '\0'; k++)
alpar@1
   440
         {  if (k == 256)
alpar@1
   441
               xerror("glp_set_row_name: i = %d; row name too long\n",
alpar@1
   442
                  i);
alpar@1
   443
            if (iscntrl((unsigned char)name[k]))
alpar@1
   444
               xerror("glp_set_row_name: i = %d: row name contains inva"
alpar@1
   445
                  "lid character(s)\n", i);
alpar@1
   446
         }
alpar@1
   447
         row->name = dmp_get_atom(lp->pool, strlen(name)+1);
alpar@1
   448
         strcpy(row->name, name);
alpar@1
   449
         if (lp->r_tree != NULL)
alpar@1
   450
         {  xassert(row->node == NULL);
alpar@1
   451
            row->node = avl_insert_node(lp->r_tree, row->name);
alpar@1
   452
            avl_set_node_link(row->node, row);
alpar@1
   453
         }
alpar@1
   454
      }
alpar@1
   455
      return;
alpar@1
   456
}
alpar@1
   457
alpar@1
   458
/***********************************************************************
alpar@1
   459
*  NAME
alpar@1
   460
*
alpar@1
   461
*  glp_set_col_name - assign (change) column name
alpar@1
   462
*
alpar@1
   463
*  SYNOPSIS
alpar@1
   464
*
alpar@1
   465
*  void glp_set_col_name(glp_prob *lp, int j, const char *name);
alpar@1
   466
*
alpar@1
   467
*  DESCRIPTION
alpar@1
   468
*
alpar@1
   469
*  The routine glp_set_col_name assigns a given symbolic name (1 up to
alpar@1
   470
*  255 characters) to j-th column (structural variable) of the specified
alpar@1
   471
*  problem object.
alpar@1
   472
*
alpar@1
   473
*  If the parameter name is NULL or empty string, the routine erases an
alpar@1
   474
*  existing name of j-th column. */
alpar@1
   475
alpar@1
   476
void glp_set_col_name(glp_prob *lp, int j, const char *name)
alpar@1
   477
{     glp_tree *tree = lp->tree;
alpar@1
   478
      GLPCOL *col;
alpar@1
   479
      if (tree != NULL && tree->reason != 0)
alpar@1
   480
         xerror("glp_set_col_name: operation not allowed\n");
alpar@1
   481
      if (!(1 <= j && j <= lp->n))
alpar@1
   482
         xerror("glp_set_col_name: j = %d; column number out of range\n"
alpar@1
   483
            , j);
alpar@1
   484
      col = lp->col[j];
alpar@1
   485
      if (col->name != NULL)
alpar@1
   486
      {  if (col->node != NULL)
alpar@1
   487
         {  xassert(lp->c_tree != NULL);
alpar@1
   488
            avl_delete_node(lp->c_tree, col->node);
alpar@1
   489
            col->node = NULL;
alpar@1
   490
         }
alpar@1
   491
         dmp_free_atom(lp->pool, col->name, strlen(col->name)+1);
alpar@1
   492
         col->name = NULL;
alpar@1
   493
      }
alpar@1
   494
      if (!(name == NULL || name[0] == '\0'))
alpar@1
   495
      {  int k;
alpar@1
   496
         for (k = 0; name[k] != '\0'; k++)
alpar@1
   497
         {  if (k == 256)
alpar@1
   498
               xerror("glp_set_col_name: j = %d; column name too long\n"
alpar@1
   499
                  , j);
alpar@1
   500
            if (iscntrl((unsigned char)name[k]))
alpar@1
   501
               xerror("glp_set_col_name: j = %d: column name contains i"
alpar@1
   502
                  "nvalid character(s)\n", j);
alpar@1
   503
         }
alpar@1
   504
         col->name = dmp_get_atom(lp->pool, strlen(name)+1);
alpar@1
   505
         strcpy(col->name, name);
alpar@1
   506
         if (lp->c_tree != NULL && col->name != NULL)
alpar@1
   507
         {  xassert(col->node == NULL);
alpar@1
   508
            col->node = avl_insert_node(lp->c_tree, col->name);
alpar@1
   509
            avl_set_node_link(col->node, col);
alpar@1
   510
         }
alpar@1
   511
      }
alpar@1
   512
      return;
alpar@1
   513
}
alpar@1
   514
alpar@1
   515
/***********************************************************************
alpar@1
   516
*  NAME
alpar@1
   517
*
alpar@1
   518
*  glp_set_row_bnds - set (change) row bounds
alpar@1
   519
*
alpar@1
   520
*  SYNOPSIS
alpar@1
   521
*
alpar@1
   522
*  void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
alpar@1
   523
*     double ub);
alpar@1
   524
*
alpar@1
   525
*  DESCRIPTION
alpar@1
   526
*
alpar@1
   527
*  The routine glp_set_row_bnds sets (changes) the type and bounds of
alpar@1
   528
*  i-th row (auxiliary variable) of the specified problem object.
alpar@1
   529
*
alpar@1
   530
*  Parameters type, lb, and ub specify the type, lower bound, and upper
alpar@1
   531
*  bound, respectively, as follows:
alpar@1
   532
*
alpar@1
   533
*     Type           Bounds        Comments
alpar@1
   534
*     ------------------------------------------------------
alpar@1
   535
*     GLP_FR   -inf <  x <  +inf   Free variable
alpar@1
   536
*     GLP_LO     lb <= x <  +inf   Variable with lower bound
alpar@1
   537
*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
alpar@1
   538
*     GLP_DB     lb <= x <=  ub    Double-bounded variable
alpar@1
   539
*     GLP_FX           x  =  lb    Fixed variable
alpar@1
   540
*
alpar@1
   541
*  where x is the auxiliary variable associated with i-th row.
alpar@1
   542
*
alpar@1
   543
*  If the row has no lower bound, the parameter lb is ignored. If the
alpar@1
   544
*  row has no upper bound, the parameter ub is ignored. If the row is
alpar@1
   545
*  an equality constraint (i.e. the corresponding auxiliary variable is
alpar@1
   546
*  of fixed type), only the parameter lb is used while the parameter ub
alpar@1
   547
*  is ignored. */
alpar@1
   548
alpar@1
   549
void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb,
alpar@1
   550
      double ub)
alpar@1
   551
{     GLPROW *row;
alpar@1
   552
      if (!(1 <= i && i <= lp->m))
alpar@1
   553
         xerror("glp_set_row_bnds: i = %d; row number out of range\n",
alpar@1
   554
            i);
alpar@1
   555
      row = lp->row[i];
alpar@1
   556
      row->type = type;
alpar@1
   557
      switch (type)
alpar@1
   558
      {  case GLP_FR:
alpar@1
   559
            row->lb = row->ub = 0.0;
alpar@1
   560
            if (row->stat != GLP_BS) row->stat = GLP_NF;
alpar@1
   561
            break;
alpar@1
   562
         case GLP_LO:
alpar@1
   563
            row->lb = lb, row->ub = 0.0;
alpar@1
   564
            if (row->stat != GLP_BS) row->stat = GLP_NL;
alpar@1
   565
            break;
alpar@1
   566
         case GLP_UP:
alpar@1
   567
            row->lb = 0.0, row->ub = ub;
alpar@1
   568
            if (row->stat != GLP_BS) row->stat = GLP_NU;
alpar@1
   569
            break;
alpar@1
   570
         case GLP_DB:
alpar@1
   571
            row->lb = lb, row->ub = ub;
alpar@1
   572
            if (!(row->stat == GLP_BS ||
alpar@1
   573
                  row->stat == GLP_NL || row->stat == GLP_NU))
alpar@1
   574
               row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
alpar@1
   575
            break;
alpar@1
   576
         case GLP_FX:
alpar@1
   577
            row->lb = row->ub = lb;
alpar@1
   578
            if (row->stat != GLP_BS) row->stat = GLP_NS;
alpar@1
   579
            break;
alpar@1
   580
         default:
alpar@1
   581
            xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty"
alpar@1
   582
               "pe\n", i, type);
alpar@1
   583
      }
alpar@1
   584
      return;
alpar@1
   585
}
alpar@1
   586
alpar@1
   587
/***********************************************************************
alpar@1
   588
*  NAME
alpar@1
   589
*
alpar@1
   590
*  glp_set_col_bnds - set (change) column bounds
alpar@1
   591
*
alpar@1
   592
*  SYNOPSIS
alpar@1
   593
*
alpar@1
   594
*  void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
alpar@1
   595
*     double ub);
alpar@1
   596
*
alpar@1
   597
*  DESCRIPTION
alpar@1
   598
*
alpar@1
   599
*  The routine glp_set_col_bnds sets (changes) the type and bounds of
alpar@1
   600
*  j-th column (structural variable) of the specified problem object.
alpar@1
   601
*
alpar@1
   602
*  Parameters type, lb, and ub specify the type, lower bound, and upper
alpar@1
   603
*  bound, respectively, as follows:
alpar@1
   604
*
alpar@1
   605
*     Type           Bounds        Comments
alpar@1
   606
*     ------------------------------------------------------
alpar@1
   607
*     GLP_FR   -inf <  x <  +inf   Free variable
alpar@1
   608
*     GLP_LO     lb <= x <  +inf   Variable with lower bound
alpar@1
   609
*     GLP_UP   -inf <  x <=  ub    Variable with upper bound
alpar@1
   610
*     GLP_DB     lb <= x <=  ub    Double-bounded variable
alpar@1
   611
*     GLP_FX           x  =  lb    Fixed variable
alpar@1
   612
*
alpar@1
   613
*  where x is the structural variable associated with j-th column.
alpar@1
   614
*
alpar@1
   615
*  If the column has no lower bound, the parameter lb is ignored. If the
alpar@1
   616
*  column has no upper bound, the parameter ub is ignored. If the column
alpar@1
   617
*  is of fixed type, only the parameter lb is used while the parameter
alpar@1
   618
*  ub is ignored. */
alpar@1
   619
alpar@1
   620
void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb,
alpar@1
   621
      double ub)
alpar@1
   622
{     GLPCOL *col;
alpar@1
   623
      if (!(1 <= j && j <= lp->n))
alpar@1
   624
         xerror("glp_set_col_bnds: j = %d; column number out of range\n"
alpar@1
   625
            , j);
alpar@1
   626
      col = lp->col[j];
alpar@1
   627
      col->type = type;
alpar@1
   628
      switch (type)
alpar@1
   629
      {  case GLP_FR:
alpar@1
   630
            col->lb = col->ub = 0.0;
alpar@1
   631
            if (col->stat != GLP_BS) col->stat = GLP_NF;
alpar@1
   632
            break;
alpar@1
   633
         case GLP_LO:
alpar@1
   634
            col->lb = lb, col->ub = 0.0;
alpar@1
   635
            if (col->stat != GLP_BS) col->stat = GLP_NL;
alpar@1
   636
            break;
alpar@1
   637
         case GLP_UP:
alpar@1
   638
            col->lb = 0.0, col->ub = ub;
alpar@1
   639
            if (col->stat != GLP_BS) col->stat = GLP_NU;
alpar@1
   640
            break;
alpar@1
   641
         case GLP_DB:
alpar@1
   642
            col->lb = lb, col->ub = ub;
alpar@1
   643
            if (!(col->stat == GLP_BS ||
alpar@1
   644
                  col->stat == GLP_NL || col->stat == GLP_NU))
alpar@1
   645
               col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU);
alpar@1
   646
            break;
alpar@1
   647
         case GLP_FX:
alpar@1
   648
            col->lb = col->ub = lb;
alpar@1
   649
            if (col->stat != GLP_BS) col->stat = GLP_NS;
alpar@1
   650
            break;
alpar@1
   651
         default:
alpar@1
   652
            xerror("glp_set_col_bnds: j = %d; type = %d; invalid column"
alpar@1
   653
               " type\n", j, type);
alpar@1
   654
      }
alpar@1
   655
      return;
alpar@1
   656
}
alpar@1
   657
alpar@1
   658
/***********************************************************************
alpar@1
   659
*  NAME
alpar@1
   660
*
alpar@1
   661
*  glp_set_obj_coef - set (change) obj. coefficient or constant term
alpar@1
   662
*
alpar@1
   663
*  SYNOPSIS
alpar@1
   664
*
alpar@1
   665
*  void glp_set_obj_coef(glp_prob *lp, int j, double coef);
alpar@1
   666
*
alpar@1
   667
*  DESCRIPTION
alpar@1
   668
*
alpar@1
   669
*  The routine glp_set_obj_coef sets (changes) objective coefficient at
alpar@1
   670
*  j-th column (structural variable) of the specified problem object.
alpar@1
   671
*
alpar@1
   672
*  If the parameter j is 0, the routine sets (changes) the constant term
alpar@1
   673
*  ("shift") of the objective function. */
alpar@1
   674
alpar@1
   675
void glp_set_obj_coef(glp_prob *lp, int j, double coef)
alpar@1
   676
{     glp_tree *tree = lp->tree;
alpar@1
   677
      if (tree != NULL && tree->reason != 0)
alpar@1
   678
         xerror("glp_set_obj_coef: operation not allowed\n");
alpar@1
   679
      if (!(0 <= j && j <= lp->n))
alpar@1
   680
         xerror("glp_set_obj_coef: j = %d; column number out of range\n"
alpar@1
   681
            , j);
alpar@1
   682
      if (j == 0)
alpar@1
   683
         lp->c0 = coef;
alpar@1
   684
      else
alpar@1
   685
         lp->col[j]->coef = coef;
alpar@1
   686
      return;
alpar@1
   687
}
alpar@1
   688
alpar@1
   689
/***********************************************************************
alpar@1
   690
*  NAME
alpar@1
   691
*
alpar@1
   692
*  glp_set_mat_row - set (replace) row of the constraint matrix
alpar@1
   693
*
alpar@1
   694
*  SYNOPSIS
alpar@1
   695
*
alpar@1
   696
*  void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
alpar@1
   697
*     const double val[]);
alpar@1
   698
*
alpar@1
   699
*  DESCRIPTION
alpar@1
   700
*
alpar@1
   701
*  The routine glp_set_mat_row stores (replaces) the contents of i-th
alpar@1
   702
*  row of the constraint matrix of the specified problem object.
alpar@1
   703
*
alpar@1
   704
*  Column indices and numeric values of new row elements must be placed
alpar@1
   705
*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
alpar@1
   706
*  0 <= len <= n is the new length of i-th row, n is the current number
alpar@1
   707
*  of columns in the problem object. Elements with identical column
alpar@1
   708
*  indices are not allowed. Zero elements are allowed, but they are not
alpar@1
   709
*  stored in the constraint matrix.
alpar@1
   710
*
alpar@1
   711
*  If the parameter len is zero, the parameters ind and/or val can be
alpar@1
   712
*  specified as NULL. */
alpar@1
   713
alpar@1
   714
void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[],
alpar@1
   715
      const double val[])
alpar@1
   716
{     glp_tree *tree = lp->tree;
alpar@1
   717
      GLPROW *row;
alpar@1
   718
      GLPCOL *col;
alpar@1
   719
      GLPAIJ *aij, *next;
alpar@1
   720
      int j, k;
alpar@1
   721
      /* obtain pointer to i-th row */
alpar@1
   722
      if (!(1 <= i && i <= lp->m))
alpar@1
   723
         xerror("glp_set_mat_row: i = %d; row number out of range\n",
alpar@1
   724
            i);
alpar@1
   725
      row = lp->row[i];
alpar@1
   726
      if (tree != NULL && tree->reason != 0)
alpar@1
   727
      {  xassert(tree->curr != NULL);
alpar@1
   728
         xassert(row->level == tree->curr->level);
alpar@1
   729
      }
alpar@1
   730
      /* remove all existing elements from i-th row */
alpar@1
   731
      while (row->ptr != NULL)
alpar@1
   732
      {  /* take next element in the row */
alpar@1
   733
         aij = row->ptr;
alpar@1
   734
         /* remove the element from the row list */
alpar@1
   735
         row->ptr = aij->r_next;
alpar@1
   736
         /* obtain pointer to corresponding column */
alpar@1
   737
         col = aij->col;
alpar@1
   738
         /* remove the element from the column list */
alpar@1
   739
         if (aij->c_prev == NULL)
alpar@1
   740
            col->ptr = aij->c_next;
alpar@1
   741
         else
alpar@1
   742
            aij->c_prev->c_next = aij->c_next;
alpar@1
   743
         if (aij->c_next == NULL)
alpar@1
   744
            ;
alpar@1
   745
         else
alpar@1
   746
            aij->c_next->c_prev = aij->c_prev;
alpar@1
   747
         /* return the element to the memory pool */
alpar@1
   748
         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
   749
         /* if the corresponding column is basic, invalidate the basis
alpar@1
   750
            factorization */
alpar@1
   751
         if (col->stat == GLP_BS) lp->valid = 0;
alpar@1
   752
      }
alpar@1
   753
      /* store new contents of i-th row */
alpar@1
   754
      if (!(0 <= len && len <= lp->n))
alpar@1
   755
         xerror("glp_set_mat_row: i = %d; len = %d; invalid row length "
alpar@1
   756
            "\n", i, len);
alpar@1
   757
      if (len > NNZ_MAX - lp->nnz)
alpar@1
   758
         xerror("glp_set_mat_row: i = %d; len = %d; too many constraint"
alpar@1
   759
            " coefficients\n", i, len);
alpar@1
   760
      for (k = 1; k <= len; k++)
alpar@1
   761
      {  /* take number j of corresponding column */
alpar@1
   762
         j = ind[k];
alpar@1
   763
         /* obtain pointer to j-th column */
alpar@1
   764
         if (!(1 <= j && j <= lp->n))
alpar@1
   765
            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index"
alpar@1
   766
               " out of range\n", i, k, j);
alpar@1
   767
         col = lp->col[j];
alpar@1
   768
         /* if there is element with the same column index, it can only
alpar@1
   769
            be found in the beginning of j-th column list */
alpar@1
   770
         if (col->ptr != NULL && col->ptr->row->i == i)
alpar@1
   771
            xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co"
alpar@1
   772
               "lumn indices not allowed\n", i, k, j);
alpar@1
   773
         /* create new element */
alpar@1
   774
         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
alpar@1
   775
         aij->row = row;
alpar@1
   776
         aij->col = col;
alpar@1
   777
         aij->val = val[k];
alpar@1
   778
         /* add the new element to the beginning of i-th row and j-th
alpar@1
   779
            column lists */
alpar@1
   780
         aij->r_prev = NULL;
alpar@1
   781
         aij->r_next = row->ptr;
alpar@1
   782
         aij->c_prev = NULL;
alpar@1
   783
         aij->c_next = col->ptr;
alpar@1
   784
         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
alpar@1
   785
         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
alpar@1
   786
         row->ptr = col->ptr = aij;
alpar@1
   787
         /* if the corresponding column is basic, invalidate the basis
alpar@1
   788
            factorization */
alpar@1
   789
         if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0;
alpar@1
   790
      }
alpar@1
   791
      /* remove zero elements from i-th row */
alpar@1
   792
      for (aij = row->ptr; aij != NULL; aij = next)
alpar@1
   793
      {  next = aij->r_next;
alpar@1
   794
         if (aij->val == 0.0)
alpar@1
   795
         {  /* remove the element from the row list */
alpar@1
   796
            if (aij->r_prev == NULL)
alpar@1
   797
               row->ptr = next;
alpar@1
   798
            else
alpar@1
   799
               aij->r_prev->r_next = next;
alpar@1
   800
            if (next == NULL)
alpar@1
   801
               ;
alpar@1
   802
            else
alpar@1
   803
               next->r_prev = aij->r_prev;
alpar@1
   804
            /* remove the element from the column list */
alpar@1
   805
            xassert(aij->c_prev == NULL);
alpar@1
   806
            aij->col->ptr = aij->c_next;
alpar@1
   807
            if (aij->c_next != NULL) aij->c_next->c_prev = NULL;
alpar@1
   808
            /* return the element to the memory pool */
alpar@1
   809
            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
   810
         }
alpar@1
   811
      }
alpar@1
   812
      return;
alpar@1
   813
}
alpar@1
   814
alpar@1
   815
/***********************************************************************
alpar@1
   816
*  NAME
alpar@1
   817
*
alpar@1
   818
*  glp_set_mat_col - set (replace) column of the constraint matrix
alpar@1
   819
*
alpar@1
   820
*  SYNOPSIS
alpar@1
   821
*
alpar@1
   822
*  void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
alpar@1
   823
*     const double val[]);
alpar@1
   824
*
alpar@1
   825
*  DESCRIPTION
alpar@1
   826
*
alpar@1
   827
*  The routine glp_set_mat_col stores (replaces) the contents of j-th
alpar@1
   828
*  column of the constraint matrix of the specified problem object.
alpar@1
   829
*
alpar@1
   830
*  Row indices and numeric values of new column elements must be placed
alpar@1
   831
*  in locations ind[1], ..., ind[len] and val[1], ..., val[len], where
alpar@1
   832
*  0 <= len <= m is the new length of j-th column, m is the current
alpar@1
   833
*  number of rows in the problem object. Elements with identical column
alpar@1
   834
*  indices are not allowed. Zero elements are allowed, but they are not
alpar@1
   835
*  stored in the constraint matrix.
alpar@1
   836
*
alpar@1
   837
*  If the parameter len is zero, the parameters ind and/or val can be
alpar@1
   838
*  specified as NULL. */
alpar@1
   839
alpar@1
   840
void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[],
alpar@1
   841
      const double val[])
alpar@1
   842
{     glp_tree *tree = lp->tree;
alpar@1
   843
      GLPROW *row;
alpar@1
   844
      GLPCOL *col;
alpar@1
   845
      GLPAIJ *aij, *next;
alpar@1
   846
      int i, k;
alpar@1
   847
      if (tree != NULL && tree->reason != 0)
alpar@1
   848
         xerror("glp_set_mat_col: operation not allowed\n");
alpar@1
   849
      /* obtain pointer to j-th column */
alpar@1
   850
      if (!(1 <= j && j <= lp->n))
alpar@1
   851
         xerror("glp_set_mat_col: j = %d; column number out of range\n",
alpar@1
   852
            j);
alpar@1
   853
      col = lp->col[j];
alpar@1
   854
      /* remove all existing elements from j-th column */
alpar@1
   855
      while (col->ptr != NULL)
alpar@1
   856
      {  /* take next element in the column */
alpar@1
   857
         aij = col->ptr;
alpar@1
   858
         /* remove the element from the column list */
alpar@1
   859
         col->ptr = aij->c_next;
alpar@1
   860
         /* obtain pointer to corresponding row */
alpar@1
   861
         row = aij->row;
alpar@1
   862
         /* remove the element from the row list */
alpar@1
   863
         if (aij->r_prev == NULL)
alpar@1
   864
            row->ptr = aij->r_next;
alpar@1
   865
         else
alpar@1
   866
            aij->r_prev->r_next = aij->r_next;
alpar@1
   867
         if (aij->r_next == NULL)
alpar@1
   868
            ;
alpar@1
   869
         else
alpar@1
   870
            aij->r_next->r_prev = aij->r_prev;
alpar@1
   871
         /* return the element to the memory pool */
alpar@1
   872
         dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
   873
      }
alpar@1
   874
      /* store new contents of j-th column */
alpar@1
   875
      if (!(0 <= len && len <= lp->m))
alpar@1
   876
         xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng"
alpar@1
   877
            "th\n", j, len);
alpar@1
   878
      if (len > NNZ_MAX - lp->nnz)
alpar@1
   879
         xerror("glp_set_mat_col: j = %d; len = %d; too many constraint"
alpar@1
   880
            " coefficients\n", j, len);
alpar@1
   881
      for (k = 1; k <= len; k++)
alpar@1
   882
      {  /* take number i of corresponding row */
alpar@1
   883
         i = ind[k];
alpar@1
   884
         /* obtain pointer to i-th row */
alpar@1
   885
         if (!(1 <= i && i <= lp->m))
alpar@1
   886
            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou"
alpar@1
   887
               "t of range\n", j, k, i);
alpar@1
   888
         row = lp->row[i];
alpar@1
   889
         /* if there is element with the same row index, it can only be
alpar@1
   890
            found in the beginning of i-th row list */
alpar@1
   891
         if (row->ptr != NULL && row->ptr->col->j == j)
alpar@1
   892
            xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro"
alpar@1
   893
               "w indices not allowed\n", j, k, i);
alpar@1
   894
         /* create new element */
alpar@1
   895
         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
alpar@1
   896
         aij->row = row;
alpar@1
   897
         aij->col = col;
alpar@1
   898
         aij->val = val[k];
alpar@1
   899
         /* add the new element to the beginning of i-th row and j-th
alpar@1
   900
            column lists */
alpar@1
   901
         aij->r_prev = NULL;
alpar@1
   902
         aij->r_next = row->ptr;
alpar@1
   903
         aij->c_prev = NULL;
alpar@1
   904
         aij->c_next = col->ptr;
alpar@1
   905
         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
alpar@1
   906
         if (aij->c_next != NULL) aij->c_next->c_prev = aij;
alpar@1
   907
         row->ptr = col->ptr = aij;
alpar@1
   908
      }
alpar@1
   909
      /* remove zero elements from j-th column */
alpar@1
   910
      for (aij = col->ptr; aij != NULL; aij = next)
alpar@1
   911
      {  next = aij->c_next;
alpar@1
   912
         if (aij->val == 0.0)
alpar@1
   913
         {  /* remove the element from the row list */
alpar@1
   914
            xassert(aij->r_prev == NULL);
alpar@1
   915
            aij->row->ptr = aij->r_next;
alpar@1
   916
            if (aij->r_next != NULL) aij->r_next->r_prev = NULL;
alpar@1
   917
            /* remove the element from the column list */
alpar@1
   918
            if (aij->c_prev == NULL)
alpar@1
   919
               col->ptr = next;
alpar@1
   920
            else
alpar@1
   921
               aij->c_prev->c_next = next;
alpar@1
   922
            if (next == NULL)
alpar@1
   923
               ;
alpar@1
   924
            else
alpar@1
   925
               next->c_prev = aij->c_prev;
alpar@1
   926
            /* return the element to the memory pool */
alpar@1
   927
            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
   928
         }
alpar@1
   929
      }
alpar@1
   930
      /* if j-th column is basic, invalidate the basis factorization */
alpar@1
   931
      if (col->stat == GLP_BS) lp->valid = 0;
alpar@1
   932
      return;
alpar@1
   933
}
alpar@1
   934
alpar@1
   935
/***********************************************************************
alpar@1
   936
*  NAME
alpar@1
   937
*
alpar@1
   938
*  glp_load_matrix - load (replace) the whole constraint matrix
alpar@1
   939
*
alpar@1
   940
*  SYNOPSIS
alpar@1
   941
*
alpar@1
   942
*  void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
alpar@1
   943
*     const int ja[], const double ar[]);
alpar@1
   944
*
alpar@1
   945
*  DESCRIPTION
alpar@1
   946
*
alpar@1
   947
*  The routine glp_load_matrix loads the constraint matrix passed in
alpar@1
   948
*  the arrays ia, ja, and ar into the specified problem object. Before
alpar@1
   949
*  loading the current contents of the constraint matrix is destroyed.
alpar@1
   950
*
alpar@1
   951
*  Constraint coefficients (elements of the constraint matrix) must be
alpar@1
   952
*  specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne,
alpar@1
   953
*  where ia[k] is the row index, ja[k] is the column index, ar[k] is a
alpar@1
   954
*  numeric value of corresponding constraint coefficient. The parameter
alpar@1
   955
*  ne specifies the total number of (non-zero) elements in the matrix
alpar@1
   956
*  to be loaded. Coefficients with identical indices are not allowed.
alpar@1
   957
*  Zero coefficients are allowed, however, they are not stored in the
alpar@1
   958
*  constraint matrix.
alpar@1
   959
*
alpar@1
   960
*  If the parameter ne is zero, the parameters ia, ja, and ar can be
alpar@1
   961
*  specified as NULL. */
alpar@1
   962
alpar@1
   963
void glp_load_matrix(glp_prob *lp, int ne, const int ia[],
alpar@1
   964
      const int ja[], const double ar[])
alpar@1
   965
{     glp_tree *tree = lp->tree;
alpar@1
   966
      GLPROW *row;
alpar@1
   967
      GLPCOL *col;
alpar@1
   968
      GLPAIJ *aij, *next;
alpar@1
   969
      int i, j, k;
alpar@1
   970
      if (tree != NULL && tree->reason != 0)
alpar@1
   971
         xerror("glp_load_matrix: operation not allowed\n");
alpar@1
   972
      /* clear the constraint matrix */
alpar@1
   973
      for (i = 1; i <= lp->m; i++)
alpar@1
   974
      {  row = lp->row[i];
alpar@1
   975
         while (row->ptr != NULL)
alpar@1
   976
         {  aij = row->ptr;
alpar@1
   977
            row->ptr = aij->r_next;
alpar@1
   978
            dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
   979
         }
alpar@1
   980
      }
alpar@1
   981
      xassert(lp->nnz == 0);
alpar@1
   982
      for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL;
alpar@1
   983
      /* load the new contents of the constraint matrix and build its
alpar@1
   984
         row lists */
alpar@1
   985
      if (ne < 0)
alpar@1
   986
         xerror("glp_load_matrix: ne = %d; invalid number of constraint"
alpar@1
   987
            " coefficients\n", ne);
alpar@1
   988
      if (ne > NNZ_MAX)
alpar@1
   989
         xerror("glp_load_matrix: ne = %d; too many constraint coeffici"
alpar@1
   990
            "ents\n", ne);
alpar@1
   991
      for (k = 1; k <= ne; k++)
alpar@1
   992
      {  /* take indices of new element */
alpar@1
   993
         i = ia[k], j = ja[k];
alpar@1
   994
         /* obtain pointer to i-th row */
alpar@1
   995
         if (!(1 <= i && i <= lp->m))
alpar@1
   996
            xerror("glp_load_matrix: ia[%d] = %d; row index out of rang"
alpar@1
   997
               "e\n", k, i);
alpar@1
   998
         row = lp->row[i];
alpar@1
   999
         /* obtain pointer to j-th column */
alpar@1
  1000
         if (!(1 <= j && j <= lp->n))
alpar@1
  1001
            xerror("glp_load_matrix: ja[%d] = %d; column index out of r"
alpar@1
  1002
               "ange\n", k, j);
alpar@1
  1003
         col = lp->col[j];
alpar@1
  1004
         /* create new element */
alpar@1
  1005
         aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++;
alpar@1
  1006
         aij->row = row;
alpar@1
  1007
         aij->col = col;
alpar@1
  1008
         aij->val = ar[k];
alpar@1
  1009
         /* add the new element to the beginning of i-th row list */
alpar@1
  1010
         aij->r_prev = NULL;
alpar@1
  1011
         aij->r_next = row->ptr;
alpar@1
  1012
         if (aij->r_next != NULL) aij->r_next->r_prev = aij;
alpar@1
  1013
         row->ptr = aij;
alpar@1
  1014
      }
alpar@1
  1015
      xassert(lp->nnz == ne);
alpar@1
  1016
      /* build column lists of the constraint matrix and check elements
alpar@1
  1017
         with identical indices */
alpar@1
  1018
      for (i = 1; i <= lp->m; i++)
alpar@1
  1019
      {  for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  1020
         {  /* obtain pointer to corresponding column */
alpar@1
  1021
            col = aij->col;
alpar@1
  1022
            /* if there is element with identical indices, it can only
alpar@1
  1023
               be found in the beginning of j-th column list */
alpar@1
  1024
            if (col->ptr != NULL && col->ptr->row->i == i)
alpar@1
  1025
            {  for (k = 1; k <= ne; k++)
alpar@1
  1026
                  if (ia[k] == i && ja[k] == col->j) break;
alpar@1
  1027
               xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat"
alpar@1
  1028
                  "e indices not allowed\n", k, i, k, col->j);
alpar@1
  1029
            }
alpar@1
  1030
            /* add the element to the beginning of j-th column list */
alpar@1
  1031
            aij->c_prev = NULL;
alpar@1
  1032
            aij->c_next = col->ptr;
alpar@1
  1033
            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
alpar@1
  1034
            col->ptr = aij;
alpar@1
  1035
         }
alpar@1
  1036
      }
alpar@1
  1037
      /* remove zero elements from the constraint matrix */
alpar@1
  1038
      for (i = 1; i <= lp->m; i++)
alpar@1
  1039
      {  row = lp->row[i];
alpar@1
  1040
         for (aij = row->ptr; aij != NULL; aij = next)
alpar@1
  1041
         {  next = aij->r_next;
alpar@1
  1042
            if (aij->val == 0.0)
alpar@1
  1043
            {  /* remove the element from the row list */
alpar@1
  1044
               if (aij->r_prev == NULL)
alpar@1
  1045
                  row->ptr = next;
alpar@1
  1046
               else
alpar@1
  1047
                  aij->r_prev->r_next = next;
alpar@1
  1048
               if (next == NULL)
alpar@1
  1049
                  ;
alpar@1
  1050
               else
alpar@1
  1051
                  next->r_prev = aij->r_prev;
alpar@1
  1052
               /* remove the element from the column list */
alpar@1
  1053
               if (aij->c_prev == NULL)
alpar@1
  1054
                  aij->col->ptr = aij->c_next;
alpar@1
  1055
               else
alpar@1
  1056
                  aij->c_prev->c_next = aij->c_next;
alpar@1
  1057
               if (aij->c_next == NULL)
alpar@1
  1058
                  ;
alpar@1
  1059
               else
alpar@1
  1060
                  aij->c_next->c_prev = aij->c_prev;
alpar@1
  1061
               /* return the element to the memory pool */
alpar@1
  1062
               dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--;
alpar@1
  1063
            }
alpar@1
  1064
         }
alpar@1
  1065
      }
alpar@1
  1066
      /* invalidate the basis factorization */
alpar@1
  1067
      lp->valid = 0;
alpar@1
  1068
      return;
alpar@1
  1069
}
alpar@1
  1070
alpar@1
  1071
/***********************************************************************
alpar@1
  1072
*  NAME
alpar@1
  1073
*
alpar@1
  1074
*  glp_check_dup - check for duplicate elements in sparse matrix
alpar@1
  1075
*
alpar@1
  1076
*  SYNOPSIS
alpar@1
  1077
*
alpar@1
  1078
*  int glp_check_dup(int m, int n, int ne, const int ia[],
alpar@1
  1079
*     const int ja[]);
alpar@1
  1080
*
alpar@1
  1081
*  DESCRIPTION
alpar@1
  1082
*
alpar@1
  1083
*  The routine glp_check_dup checks for duplicate elements (that is,
alpar@1
  1084
*  elements with identical indices) in a sparse matrix specified in the
alpar@1
  1085
*  coordinate format.
alpar@1
  1086
*
alpar@1
  1087
*  The parameters m and n specifies, respectively, the number of rows
alpar@1
  1088
*  and columns in the matrix, m >= 0, n >= 0.
alpar@1
  1089
*
alpar@1
  1090
*  The parameter ne specifies the number of (structurally) non-zero
alpar@1
  1091
*  elements in the matrix, ne >= 0.
alpar@1
  1092
*
alpar@1
  1093
*  Elements of the matrix are specified as doublets (ia[k],ja[k]) for
alpar@1
  1094
*  k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index.
alpar@1
  1095
*
alpar@1
  1096
*  The routine glp_check_dup can be used prior to a call to the routine
alpar@1
  1097
*  glp_load_matrix to check that the constraint matrix to be loaded has
alpar@1
  1098
*  no duplicate elements.
alpar@1
  1099
*
alpar@1
  1100
*  RETURNS
alpar@1
  1101
*
alpar@1
  1102
*  The routine glp_check_dup returns one of the following values:
alpar@1
  1103
*
alpar@1
  1104
*   0 - the matrix has no duplicate elements;
alpar@1
  1105
*
alpar@1
  1106
*  -k - indices ia[k] or/and ja[k] are out of range;
alpar@1
  1107
*
alpar@1
  1108
*  +k - element (ia[k],ja[k]) is duplicate. */
alpar@1
  1109
alpar@1
  1110
int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[])
alpar@1
  1111
{     int i, j, k, *ptr, *next, ret;
alpar@1
  1112
      char *flag;
alpar@1
  1113
      if (m < 0)
alpar@1
  1114
         xerror("glp_check_dup: m = %d; invalid parameter\n");
alpar@1
  1115
      if (n < 0)
alpar@1
  1116
         xerror("glp_check_dup: n = %d; invalid parameter\n");
alpar@1
  1117
      if (ne < 0)
alpar@1
  1118
         xerror("glp_check_dup: ne = %d; invalid parameter\n");
alpar@1
  1119
      if (ne > 0 && ia == NULL)
alpar@1
  1120
         xerror("glp_check_dup: ia = %p; invalid parameter\n", ia);
alpar@1
  1121
      if (ne > 0 && ja == NULL)
alpar@1
  1122
         xerror("glp_check_dup: ja = %p; invalid parameter\n", ja);
alpar@1
  1123
      for (k = 1; k <= ne; k++)
alpar@1
  1124
      {  i = ia[k], j = ja[k];
alpar@1
  1125
         if (!(1 <= i && i <= m && 1 <= j && j <= n))
alpar@1
  1126
         {  ret = -k;
alpar@1
  1127
            goto done;
alpar@1
  1128
         }
alpar@1
  1129
      }
alpar@1
  1130
      if (m == 0 || n == 0)
alpar@1
  1131
      {  ret = 0;
alpar@1
  1132
         goto done;
alpar@1
  1133
      }
alpar@1
  1134
      /* allocate working arrays */
alpar@1
  1135
      ptr = xcalloc(1+m, sizeof(int));
alpar@1
  1136
      next = xcalloc(1+ne, sizeof(int));
alpar@1
  1137
      flag = xcalloc(1+n, sizeof(char));
alpar@1
  1138
      /* build row lists */
alpar@1
  1139
      for (i = 1; i <= m; i++)
alpar@1
  1140
         ptr[i] = 0;
alpar@1
  1141
      for (k = 1; k <= ne; k++)
alpar@1
  1142
      {  i = ia[k];
alpar@1
  1143
         next[k] = ptr[i];
alpar@1
  1144
         ptr[i] = k;
alpar@1
  1145
      }
alpar@1
  1146
      /* clear column flags */
alpar@1
  1147
      for (j = 1; j <= n; j++)
alpar@1
  1148
         flag[j] = 0;
alpar@1
  1149
      /* check for duplicate elements */
alpar@1
  1150
      for (i = 1; i <= m; i++)
alpar@1
  1151
      {  for (k = ptr[i]; k != 0; k = next[k])
alpar@1
  1152
         {  j = ja[k];
alpar@1
  1153
            if (flag[j])
alpar@1
  1154
            {  /* find first element (i,j) */
alpar@1
  1155
               for (k = 1; k <= ne; k++)
alpar@1
  1156
                  if (ia[k] == i && ja[k] == j) break;
alpar@1
  1157
               xassert(k <= ne);
alpar@1
  1158
               /* find next (duplicate) element (i,j) */
alpar@1
  1159
               for (k++; k <= ne; k++)
alpar@1
  1160
                  if (ia[k] == i && ja[k] == j) break;
alpar@1
  1161
               xassert(k <= ne);
alpar@1
  1162
               ret = +k;
alpar@1
  1163
               goto skip;
alpar@1
  1164
            }
alpar@1
  1165
            flag[j] = 1;
alpar@1
  1166
         }
alpar@1
  1167
         /* clear column flags */
alpar@1
  1168
         for (k = ptr[i]; k != 0; k = next[k])
alpar@1
  1169
            flag[ja[k]] = 0;
alpar@1
  1170
      }
alpar@1
  1171
      /* no duplicate element found */
alpar@1
  1172
      ret = 0;
alpar@1
  1173
skip: /* free working arrays */
alpar@1
  1174
      xfree(ptr);
alpar@1
  1175
      xfree(next);
alpar@1
  1176
      xfree(flag);
alpar@1
  1177
done: return ret;
alpar@1
  1178
}
alpar@1
  1179
alpar@1
  1180
/***********************************************************************
alpar@1
  1181
*  NAME
alpar@1
  1182
*
alpar@1
  1183
*  glp_sort_matrix - sort elements of the constraint matrix
alpar@1
  1184
*
alpar@1
  1185
*  SYNOPSIS
alpar@1
  1186
*
alpar@1
  1187
*  void glp_sort_matrix(glp_prob *P);
alpar@1
  1188
*
alpar@1
  1189
*  DESCRIPTION
alpar@1
  1190
*
alpar@1
  1191
*  The routine glp_sort_matrix sorts elements of the constraint matrix
alpar@1
  1192
*  rebuilding its row and column linked lists. On exit from the routine
alpar@1
  1193
*  the constraint matrix is not changed, however, elements in the row
alpar@1
  1194
*  linked lists become ordered by ascending column indices, and the
alpar@1
  1195
*  elements in the column linked lists become ordered by ascending row
alpar@1
  1196
*  indices. */
alpar@1
  1197
alpar@1
  1198
void glp_sort_matrix(glp_prob *P)
alpar@1
  1199
{     GLPAIJ *aij;
alpar@1
  1200
      int i, j;
alpar@1
  1201
      if (P == NULL || P->magic != GLP_PROB_MAGIC)
alpar@1
  1202
         xerror("glp_sort_matrix: P = %p; invalid problem object\n",
alpar@1
  1203
            P);
alpar@1
  1204
      /* rebuild row linked lists */
alpar@1
  1205
      for (i = P->m; i >= 1; i--)
alpar@1
  1206
         P->row[i]->ptr = NULL;
alpar@1
  1207
      for (j = P->n; j >= 1; j--)
alpar@1
  1208
      {  for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next)
alpar@1
  1209
         {  i = aij->row->i;
alpar@1
  1210
            aij->r_prev = NULL;
alpar@1
  1211
            aij->r_next = P->row[i]->ptr;
alpar@1
  1212
            if (aij->r_next != NULL) aij->r_next->r_prev = aij;
alpar@1
  1213
            P->row[i]->ptr = aij;
alpar@1
  1214
         }
alpar@1
  1215
      }
alpar@1
  1216
      /* rebuild column linked lists */
alpar@1
  1217
      for (j = P->n; j >= 1; j--)
alpar@1
  1218
         P->col[j]->ptr = NULL;
alpar@1
  1219
      for (i = P->m; i >= 1; i--)
alpar@1
  1220
      {  for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  1221
         {  j = aij->col->j;
alpar@1
  1222
            aij->c_prev = NULL;
alpar@1
  1223
            aij->c_next = P->col[j]->ptr;
alpar@1
  1224
            if (aij->c_next != NULL) aij->c_next->c_prev = aij;
alpar@1
  1225
            P->col[j]->ptr = aij;
alpar@1
  1226
         }
alpar@1
  1227
      }
alpar@1
  1228
      return;
alpar@1
  1229
}
alpar@1
  1230
alpar@1
  1231
/***********************************************************************
alpar@1
  1232
*  NAME
alpar@1
  1233
*
alpar@1
  1234
*  glp_del_rows - delete rows from problem object
alpar@1
  1235
*
alpar@1
  1236
*  SYNOPSIS
alpar@1
  1237
*
alpar@1
  1238
*  void glp_del_rows(glp_prob *lp, int nrs, const int num[]);
alpar@1
  1239
*
alpar@1
  1240
*  DESCRIPTION
alpar@1
  1241
*
alpar@1
  1242
*  The routine glp_del_rows deletes rows from the specified problem
alpar@1
  1243
*  object. Ordinal numbers of rows to be deleted should be placed in
alpar@1
  1244
*  locations num[1], ..., num[nrs], where nrs > 0.
alpar@1
  1245
*
alpar@1
  1246
*  Note that deleting rows involves changing ordinal numbers of other
alpar@1
  1247
*  rows remaining in the problem object. New ordinal numbers of the
alpar@1
  1248
*  remaining rows are assigned under the assumption that the original
alpar@1
  1249
*  order of rows is not changed. */
alpar@1
  1250
alpar@1
  1251
void glp_del_rows(glp_prob *lp, int nrs, const int num[])
alpar@1
  1252
{     glp_tree *tree = lp->tree;
alpar@1
  1253
      GLPROW *row;
alpar@1
  1254
      int i, k, m_new;
alpar@1
  1255
      /* mark rows to be deleted */
alpar@1
  1256
      if (!(1 <= nrs && nrs <= lp->m))
alpar@1
  1257
         xerror("glp_del_rows: nrs = %d; invalid number of rows\n",
alpar@1
  1258
            nrs);
alpar@1
  1259
      for (k = 1; k <= nrs; k++)
alpar@1
  1260
      {  /* take the number of row to be deleted */
alpar@1
  1261
         i = num[k];
alpar@1
  1262
         /* obtain pointer to i-th row */
alpar@1
  1263
         if (!(1 <= i && i <= lp->m))
alpar@1
  1264
            xerror("glp_del_rows: num[%d] = %d; row number out of range"
alpar@1
  1265
               "\n", k, i);
alpar@1
  1266
         row = lp->row[i];
alpar@1
  1267
         if (tree != NULL && tree->reason != 0)
alpar@1
  1268
         {  if (!(tree->reason == GLP_IROWGEN ||
alpar@1
  1269
                  tree->reason == GLP_ICUTGEN))
alpar@1
  1270
               xerror("glp_del_rows: operation not allowed\n");
alpar@1
  1271
            xassert(tree->curr != NULL);
alpar@1
  1272
            if (row->level != tree->curr->level)
alpar@1
  1273
               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
alpar@1
  1274
                  "elete row created not in current subproblem\n", k,i);
alpar@1
  1275
            if (row->stat != GLP_BS)
alpar@1
  1276
               xerror("glp_del_rows: num[%d] = %d; invalid attempt to d"
alpar@1
  1277
                  "elete active row (constraint)\n", k, i);
alpar@1
  1278
            tree->reinv = 1;
alpar@1
  1279
         }
alpar@1
  1280
         /* check that the row is not marked yet */
alpar@1
  1281
         if (row->i == 0)
alpar@1
  1282
            xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n"
alpar@1
  1283
               "ot allowed\n", k, i);
alpar@1
  1284
         /* erase symbolic name assigned to the row */
alpar@1
  1285
         glp_set_row_name(lp, i, NULL);
alpar@1
  1286
         xassert(row->node == NULL);
alpar@1
  1287
         /* erase corresponding row of the constraint matrix */
alpar@1
  1288
         glp_set_mat_row(lp, i, 0, NULL, NULL);
alpar@1
  1289
         xassert(row->ptr == NULL);
alpar@1
  1290
         /* mark the row to be deleted */
alpar@1
  1291
         row->i = 0;
alpar@1
  1292
      }
alpar@1
  1293
      /* delete all marked rows from the row list */
alpar@1
  1294
      m_new = 0;
alpar@1
  1295
      for (i = 1; i <= lp->m; i++)
alpar@1
  1296
      {  /* obtain pointer to i-th row */
alpar@1
  1297
         row = lp->row[i];
alpar@1
  1298
         /* check if the row is marked */
alpar@1
  1299
         if (row->i == 0)
alpar@1
  1300
         {  /* it is marked, delete it */
alpar@1
  1301
            dmp_free_atom(lp->pool, row, sizeof(GLPROW));
alpar@1
  1302
         }
alpar@1
  1303
         else
alpar@1
  1304
         {  /* it is not marked; keep it */
alpar@1
  1305
            row->i = ++m_new;
alpar@1
  1306
            lp->row[row->i] = row;
alpar@1
  1307
         }
alpar@1
  1308
      }
alpar@1
  1309
      /* set new number of rows */
alpar@1
  1310
      lp->m = m_new;
alpar@1
  1311
      /* invalidate the basis factorization */
alpar@1
  1312
      lp->valid = 0;
alpar@1
  1313
      return;
alpar@1
  1314
}
alpar@1
  1315
alpar@1
  1316
/***********************************************************************
alpar@1
  1317
*  NAME
alpar@1
  1318
*
alpar@1
  1319
*  glp_del_cols - delete columns from problem object
alpar@1
  1320
*
alpar@1
  1321
*  SYNOPSIS
alpar@1
  1322
*
alpar@1
  1323
*  void glp_del_cols(glp_prob *lp, int ncs, const int num[]);
alpar@1
  1324
*
alpar@1
  1325
*  DESCRIPTION
alpar@1
  1326
*
alpar@1
  1327
*  The routine glp_del_cols deletes columns from the specified problem
alpar@1
  1328
*  object. Ordinal numbers of columns to be deleted should be placed in
alpar@1
  1329
*  locations num[1], ..., num[ncs], where ncs > 0.
alpar@1
  1330
*
alpar@1
  1331
*  Note that deleting columns involves changing ordinal numbers of
alpar@1
  1332
*  other columns remaining in the problem object. New ordinal numbers
alpar@1
  1333
*  of the remaining columns are assigned under the assumption that the
alpar@1
  1334
*  original order of columns is not changed. */
alpar@1
  1335
alpar@1
  1336
void glp_del_cols(glp_prob *lp, int ncs, const int num[])
alpar@1
  1337
{     glp_tree *tree = lp->tree;
alpar@1
  1338
      GLPCOL *col;
alpar@1
  1339
      int j, k, n_new;
alpar@1
  1340
      if (tree != NULL && tree->reason != 0)
alpar@1
  1341
         xerror("glp_del_cols: operation not allowed\n");
alpar@1
  1342
      /* mark columns to be deleted */
alpar@1
  1343
      if (!(1 <= ncs && ncs <= lp->n))
alpar@1
  1344
         xerror("glp_del_cols: ncs = %d; invalid number of columns\n",
alpar@1
  1345
            ncs);
alpar@1
  1346
      for (k = 1; k <= ncs; k++)
alpar@1
  1347
      {  /* take the number of column to be deleted */
alpar@1
  1348
         j = num[k];
alpar@1
  1349
         /* obtain pointer to j-th column */
alpar@1
  1350
         if (!(1 <= j && j <= lp->n))
alpar@1
  1351
            xerror("glp_del_cols: num[%d] = %d; column number out of ra"
alpar@1
  1352
               "nge", k, j);
alpar@1
  1353
         col = lp->col[j];
alpar@1
  1354
         /* check that the column is not marked yet */
alpar@1
  1355
         if (col->j == 0)
alpar@1
  1356
            xerror("glp_del_cols: num[%d] = %d; duplicate column number"
alpar@1
  1357
               "s not allowed\n", k, j);
alpar@1
  1358
         /* erase symbolic name assigned to the column */
alpar@1
  1359
         glp_set_col_name(lp, j, NULL);
alpar@1
  1360
         xassert(col->node == NULL);
alpar@1
  1361
         /* erase corresponding column of the constraint matrix */
alpar@1
  1362
         glp_set_mat_col(lp, j, 0, NULL, NULL);
alpar@1
  1363
         xassert(col->ptr == NULL);
alpar@1
  1364
         /* mark the column to be deleted */
alpar@1
  1365
         col->j = 0;
alpar@1
  1366
         /* if it is basic, invalidate the basis factorization */
alpar@1
  1367
         if (col->stat == GLP_BS) lp->valid = 0;
alpar@1
  1368
      }
alpar@1
  1369
      /* delete all marked columns from the column list */
alpar@1
  1370
      n_new = 0;
alpar@1
  1371
      for (j = 1; j <= lp->n; j++)
alpar@1
  1372
      {  /* obtain pointer to j-th column */
alpar@1
  1373
         col = lp->col[j];
alpar@1
  1374
         /* check if the column is marked */
alpar@1
  1375
         if (col->j == 0)
alpar@1
  1376
         {  /* it is marked; delete it */
alpar@1
  1377
            dmp_free_atom(lp->pool, col, sizeof(GLPCOL));
alpar@1
  1378
         }
alpar@1
  1379
         else
alpar@1
  1380
         {  /* it is not marked; keep it */
alpar@1
  1381
            col->j = ++n_new;
alpar@1
  1382
            lp->col[col->j] = col;
alpar@1
  1383
         }
alpar@1
  1384
      }
alpar@1
  1385
      /* set new number of columns */
alpar@1
  1386
      lp->n = n_new;
alpar@1
  1387
      /* if the basis header is still valid, adjust it */
alpar@1
  1388
      if (lp->valid)
alpar@1
  1389
      {  int m = lp->m;
alpar@1
  1390
         int *head = lp->head;
alpar@1
  1391
         for (j = 1; j <= n_new; j++)
alpar@1
  1392
         {  k = lp->col[j]->bind;
alpar@1
  1393
            if (k != 0)
alpar@1
  1394
            {  xassert(1 <= k && k <= m);
alpar@1
  1395
               head[k] = m + j;
alpar@1
  1396
            }
alpar@1
  1397
         }
alpar@1
  1398
      }
alpar@1
  1399
      return;
alpar@1
  1400
}
alpar@1
  1401
alpar@1
  1402
/***********************************************************************
alpar@1
  1403
*  NAME
alpar@1
  1404
*
alpar@1
  1405
*  glp_copy_prob - copy problem object content
alpar@1
  1406
*
alpar@1
  1407
*  SYNOPSIS
alpar@1
  1408
*
alpar@1
  1409
*  void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names);
alpar@1
  1410
*
alpar@1
  1411
*  DESCRIPTION
alpar@1
  1412
*
alpar@1
  1413
*  The routine glp_copy_prob copies the content of the problem object
alpar@1
  1414
*  prob to the problem object dest.
alpar@1
  1415
*
alpar@1
  1416
*  The parameter names is a flag. If it is non-zero, the routine also
alpar@1
  1417
*  copies all symbolic names; otherwise, if it is zero, symbolic names
alpar@1
  1418
*  are not copied. */
alpar@1
  1419
alpar@1
  1420
void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names)
alpar@1
  1421
{     glp_tree *tree = dest->tree;
alpar@1
  1422
      glp_bfcp bfcp;
alpar@1
  1423
      int i, j, len, *ind;
alpar@1
  1424
      double *val;
alpar@1
  1425
      if (tree != NULL && tree->reason != 0)
alpar@1
  1426
         xerror("glp_copy_prob: operation not allowed\n");
alpar@1
  1427
      if (dest == prob)
alpar@1
  1428
         xerror("glp_copy_prob: copying problem object to itself not al"
alpar@1
  1429
            "lowed\n");
alpar@1
  1430
      if (!(names == GLP_ON || names == GLP_OFF))
alpar@1
  1431
         xerror("glp_copy_prob: names = %d; invalid parameter\n",
alpar@1
  1432
            names);
alpar@1
  1433
      glp_erase_prob(dest);
alpar@1
  1434
      if (names && prob->name != NULL)
alpar@1
  1435
         glp_set_prob_name(dest, prob->name);
alpar@1
  1436
      if (names && prob->obj != NULL)
alpar@1
  1437
         glp_set_obj_name(dest, prob->obj);
alpar@1
  1438
      dest->dir = prob->dir;
alpar@1
  1439
      dest->c0 = prob->c0;
alpar@1
  1440
      if (prob->m > 0)
alpar@1
  1441
         glp_add_rows(dest, prob->m);
alpar@1
  1442
      if (prob->n > 0)
alpar@1
  1443
         glp_add_cols(dest, prob->n);
alpar@1
  1444
      glp_get_bfcp(prob, &bfcp);
alpar@1
  1445
      glp_set_bfcp(dest, &bfcp);
alpar@1
  1446
      dest->pbs_stat = prob->pbs_stat;
alpar@1
  1447
      dest->dbs_stat = prob->dbs_stat;
alpar@1
  1448
      dest->obj_val = prob->obj_val;
alpar@1
  1449
      dest->some = prob->some;
alpar@1
  1450
      dest->ipt_stat = prob->ipt_stat;
alpar@1
  1451
      dest->ipt_obj = prob->ipt_obj;
alpar@1
  1452
      dest->mip_stat = prob->mip_stat;
alpar@1
  1453
      dest->mip_obj = prob->mip_obj;
alpar@1
  1454
      for (i = 1; i <= prob->m; i++)
alpar@1
  1455
      {  GLPROW *to = dest->row[i];
alpar@1
  1456
         GLPROW *from = prob->row[i];
alpar@1
  1457
         if (names && from->name != NULL)
alpar@1
  1458
            glp_set_row_name(dest, i, from->name);
alpar@1
  1459
         to->type = from->type;
alpar@1
  1460
         to->lb = from->lb;
alpar@1
  1461
         to->ub = from->ub;
alpar@1
  1462
         to->rii = from->rii;
alpar@1
  1463
         to->stat = from->stat;
alpar@1
  1464
         to->prim = from->prim;
alpar@1
  1465
         to->dual = from->dual;
alpar@1
  1466
         to->pval = from->pval;
alpar@1
  1467
         to->dval = from->dval;
alpar@1
  1468
         to->mipx = from->mipx;
alpar@1
  1469
      }
alpar@1
  1470
      ind = xcalloc(1+prob->m, sizeof(int));
alpar@1
  1471
      val = xcalloc(1+prob->m, sizeof(double));
alpar@1
  1472
      for (j = 1; j <= prob->n; j++)
alpar@1
  1473
      {  GLPCOL *to = dest->col[j];
alpar@1
  1474
         GLPCOL *from = prob->col[j];
alpar@1
  1475
         if (names && from->name != NULL)
alpar@1
  1476
            glp_set_col_name(dest, j, from->name);
alpar@1
  1477
         to->kind = from->kind;
alpar@1
  1478
         to->type = from->type;
alpar@1
  1479
         to->lb = from->lb;
alpar@1
  1480
         to->ub = from->ub;
alpar@1
  1481
         to->coef = from->coef;
alpar@1
  1482
         len = glp_get_mat_col(prob, j, ind, val);
alpar@1
  1483
         glp_set_mat_col(dest, j, len, ind, val);
alpar@1
  1484
         to->sjj = from->sjj;
alpar@1
  1485
         to->stat = from->stat;
alpar@1
  1486
         to->prim = from->prim;
alpar@1
  1487
         to->dual = from->dual;
alpar@1
  1488
         to->pval = from->pval;
alpar@1
  1489
         to->dval = from->dval;
alpar@1
  1490
         to->mipx = from->mipx;
alpar@1
  1491
      }
alpar@1
  1492
      xfree(ind);
alpar@1
  1493
      xfree(val);
alpar@1
  1494
      return;
alpar@1
  1495
}
alpar@1
  1496
alpar@1
  1497
/***********************************************************************
alpar@1
  1498
*  NAME
alpar@1
  1499
*
alpar@1
  1500
*  glp_erase_prob - erase problem object content
alpar@1
  1501
*
alpar@1
  1502
*  SYNOPSIS
alpar@1
  1503
*
alpar@1
  1504
*  void glp_erase_prob(glp_prob *lp);
alpar@1
  1505
*
alpar@1
  1506
*  DESCRIPTION
alpar@1
  1507
*
alpar@1
  1508
*  The routine glp_erase_prob erases the content of the specified
alpar@1
  1509
*  problem object. The effect of this operation is the same as if the
alpar@1
  1510
*  problem object would be deleted with the routine glp_delete_prob and
alpar@1
  1511
*  then created anew with the routine glp_create_prob, with exception
alpar@1
  1512
*  that the handle (pointer) to the problem object remains valid. */
alpar@1
  1513
alpar@1
  1514
static void delete_prob(glp_prob *lp);
alpar@1
  1515
alpar@1
  1516
void glp_erase_prob(glp_prob *lp)
alpar@1
  1517
{     glp_tree *tree = lp->tree;
alpar@1
  1518
      if (tree != NULL && tree->reason != 0)
alpar@1
  1519
         xerror("glp_erase_prob: operation not allowed\n");
alpar@1
  1520
      delete_prob(lp);
alpar@1
  1521
      create_prob(lp);
alpar@1
  1522
      return;
alpar@1
  1523
}
alpar@1
  1524
alpar@1
  1525
/***********************************************************************
alpar@1
  1526
*  NAME
alpar@1
  1527
*
alpar@1
  1528
*  glp_delete_prob - delete problem object
alpar@1
  1529
*
alpar@1
  1530
*  SYNOPSIS
alpar@1
  1531
*
alpar@1
  1532
*  void glp_delete_prob(glp_prob *lp);
alpar@1
  1533
*
alpar@1
  1534
*  DESCRIPTION
alpar@1
  1535
*
alpar@1
  1536
*  The routine glp_delete_prob deletes the specified problem object and
alpar@1
  1537
*  frees all the memory allocated to it. */
alpar@1
  1538
alpar@1
  1539
static void delete_prob(glp_prob *lp)
alpar@1
  1540
{     lp->magic = 0x3F3F3F3F;
alpar@1
  1541
      dmp_delete_pool(lp->pool);
alpar@1
  1542
#if 0 /* 17/XI-2009 */
alpar@1
  1543
      xfree(lp->cps);
alpar@1
  1544
#else
alpar@1
  1545
      if (lp->parms != NULL) xfree(lp->parms);
alpar@1
  1546
#endif
alpar@1
  1547
      xassert(lp->tree == NULL);
alpar@1
  1548
#if 0
alpar@1
  1549
      if (lp->cwa != NULL) xfree(lp->cwa);
alpar@1
  1550
#endif
alpar@1
  1551
      xfree(lp->row);
alpar@1
  1552
      xfree(lp->col);
alpar@1
  1553
      if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree);
alpar@1
  1554
      if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree);
alpar@1
  1555
      xfree(lp->head);
alpar@1
  1556
      if (lp->bfcp != NULL) xfree(lp->bfcp);
alpar@1
  1557
      if (lp->bfd != NULL) bfd_delete_it(lp->bfd);
alpar@1
  1558
      return;
alpar@1
  1559
}
alpar@1
  1560
alpar@1
  1561
void glp_delete_prob(glp_prob *lp)
alpar@1
  1562
{     glp_tree *tree = lp->tree;
alpar@1
  1563
      if (tree != NULL && tree->reason != 0)
alpar@1
  1564
         xerror("glp_delete_prob: operation not allowed\n");
alpar@1
  1565
      delete_prob(lp);
alpar@1
  1566
      xfree(lp);
alpar@1
  1567
      return;
alpar@1
  1568
}
alpar@1
  1569
alpar@1
  1570
/* eof */