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