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