3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
11 * GLPK is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 * License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
27 /***********************************************************************
30 * npp_free_row - process free (unbounded) row
35 * void npp_free_row(NPP *npp, NPPROW *p);
39 * The routine npp_free_row processes row p, which is free (i.e. has
42 * -inf < sum a[p,j] x[j] < +inf. (1)
45 * PROBLEM TRANSFORMATION
47 * Constraint (1) cannot be active, so it is redundant and can be
48 * removed from the original problem.
50 * Removing row p leads to removing a column of multiplier pi[p] for
51 * this row in the dual system. Since row p has no bounds, pi[p] = 0,
52 * so removing the column does not affect the dual solution.
54 * RECOVERING BASIC SOLUTION
56 * In solution to the original problem row p is inactive constraint,
57 * so it is assigned status GLP_BS, and multiplier pi[p] is assigned
60 * RECOVERING INTERIOR-POINT SOLUTION
62 * In solution to the original problem row p is inactive constraint,
63 * so its multiplier pi[p] is assigned zero value.
65 * RECOVERING MIP SOLUTION
70 { /* free (unbounded) row */
72 /* row reference number */
75 static int rcv_free_row(NPP *npp, void *info);
77 void npp_free_row(NPP *npp, NPPROW *p)
78 { /* process free (unbounded) row */
79 struct free_row *info;
80 /* the row must be free */
81 xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
82 /* create transformation stack entry */
83 info = npp_push_tse(npp,
84 rcv_free_row, sizeof(struct free_row));
86 /* remove the row from the problem */
91 static int rcv_free_row(NPP *npp, void *_info)
92 { /* recover free (unbounded) row */
93 struct free_row *info = _info;
94 if (npp->sol == GLP_SOL)
95 npp->r_stat[info->p] = GLP_BS;
96 if (npp->sol != GLP_MIP)
97 npp->r_pi[info->p] = 0.0;
101 /***********************************************************************
104 * npp_geq_row - process row of 'not less than' type
108 * #include "glpnpp.h"
109 * void npp_geq_row(NPP *npp, NPPROW *p);
113 * The routine npp_geq_row processes row p, which is 'not less than'
114 * inequality constraint:
116 * L[p] <= sum a[p,j] x[j] (<= U[p]), (1)
119 * where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
121 * PROBLEM TRANSFORMATION
123 * Constraint (1) can be replaced by equality constraint:
125 * sum a[p,j] x[j] - s = L[p], (2)
130 * 0 <= s (<= U[p] - L[p]) (3)
132 * is a non-negative surplus variable.
134 * Since in the primal system there appears column s having the only
135 * non-zero coefficient in row p, in the dual system there appears a
138 * (-1) pi[p] + lambda = 0, (4)
140 * where (-1) is coefficient of column s in row p, pi[p] is multiplier
141 * of row p, lambda is multiplier of column q, 0 is coefficient of
142 * column s in the objective row.
144 * RECOVERING BASIC SOLUTION
146 * Status of row p in solution to the original problem is determined
147 * by its status and status of column q in solution to the transformed
148 * problem as follows:
150 * +--------------------------------------+------------------+
151 * | Transformed problem | Original problem |
152 * +-----------------+--------------------+------------------+
153 * | Status of row p | Status of column s | Status of row p |
154 * +-----------------+--------------------+------------------+
155 * | GLP_BS | GLP_BS | N/A |
156 * | GLP_BS | GLP_NL | GLP_BS |
157 * | GLP_BS | GLP_NU | GLP_BS |
158 * | GLP_NS | GLP_BS | GLP_BS |
159 * | GLP_NS | GLP_NL | GLP_NL |
160 * | GLP_NS | GLP_NU | GLP_NU |
161 * +-----------------+--------------------+------------------+
163 * Value of row multiplier pi[p] in solution to the original problem
164 * is the same as in solution to the transformed problem.
166 * 1. In solution to the transformed problem row p and column q cannot
167 * be basic at the same time; otherwise the basis matrix would have
168 * two linear dependent columns: unity column of auxiliary variable
169 * of row p and unity column of variable s.
171 * 2. Though in the transformed problem row p is equality constraint,
172 * it may be basic due to primal degenerate solution.
174 * RECOVERING INTERIOR-POINT SOLUTION
176 * Value of row multiplier pi[p] in solution to the original problem
177 * is the same as in solution to the transformed problem.
179 * RECOVERING MIP SOLUTION
184 { /* inequality constraint row */
186 /* row reference number */
188 /* column reference number for slack/surplus variable */
191 static int rcv_geq_row(NPP *npp, void *info);
193 void npp_geq_row(NPP *npp, NPPROW *p)
194 { /* process row of 'not less than' type */
195 struct ineq_row *info;
197 /* the row must have lower bound */
198 xassert(p->lb != -DBL_MAX);
199 xassert(p->lb < p->ub);
200 /* create column for surplus variable */
201 s = npp_add_col(npp);
203 s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
204 /* and add it to the transformed problem */
205 npp_add_aij(npp, p, s, -1.0);
206 /* create transformation stack entry */
207 info = npp_push_tse(npp,
208 rcv_geq_row, sizeof(struct ineq_row));
211 /* replace the row by equality constraint */
216 static int rcv_geq_row(NPP *npp, void *_info)
217 { /* recover row of 'not less than' type */
218 struct ineq_row *info = _info;
219 if (npp->sol == GLP_SOL)
220 { if (npp->r_stat[info->p] == GLP_BS)
221 { if (npp->c_stat[info->s] == GLP_BS)
225 else if (npp->c_stat[info->s] == GLP_NL ||
226 npp->c_stat[info->s] == GLP_NU)
227 npp->r_stat[info->p] = GLP_BS;
233 else if (npp->r_stat[info->p] == GLP_NS)
234 { if (npp->c_stat[info->s] == GLP_BS)
235 npp->r_stat[info->p] = GLP_BS;
236 else if (npp->c_stat[info->s] == GLP_NL)
237 npp->r_stat[info->p] = GLP_NL;
238 else if (npp->c_stat[info->s] == GLP_NU)
239 npp->r_stat[info->p] = GLP_NU;
253 /***********************************************************************
256 * npp_leq_row - process row of 'not greater than' type
260 * #include "glpnpp.h"
261 * void npp_leq_row(NPP *npp, NPPROW *p);
265 * The routine npp_leq_row processes row p, which is 'not greater than'
266 * inequality constraint:
268 * (L[p] <=) sum a[p,j] x[j] <= U[p], (1)
271 * where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
273 * PROBLEM TRANSFORMATION
275 * Constraint (1) can be replaced by equality constraint:
277 * sum a[p,j] x[j] + s = L[p], (2)
282 * 0 <= s (<= U[p] - L[p]) (3)
284 * is a non-negative slack variable.
286 * Since in the primal system there appears column s having the only
287 * non-zero coefficient in row p, in the dual system there appears a
290 * (+1) pi[p] + lambda = 0, (4)
292 * where (+1) is coefficient of column s in row p, pi[p] is multiplier
293 * of row p, lambda is multiplier of column q, 0 is coefficient of
294 * column s in the objective row.
296 * RECOVERING BASIC SOLUTION
298 * Status of row p in solution to the original problem is determined
299 * by its status and status of column q in solution to the transformed
300 * problem as follows:
302 * +--------------------------------------+------------------+
303 * | Transformed problem | Original problem |
304 * +-----------------+--------------------+------------------+
305 * | Status of row p | Status of column s | Status of row p |
306 * +-----------------+--------------------+------------------+
307 * | GLP_BS | GLP_BS | N/A |
308 * | GLP_BS | GLP_NL | GLP_BS |
309 * | GLP_BS | GLP_NU | GLP_BS |
310 * | GLP_NS | GLP_BS | GLP_BS |
311 * | GLP_NS | GLP_NL | GLP_NU |
312 * | GLP_NS | GLP_NU | GLP_NL |
313 * +-----------------+--------------------+------------------+
315 * Value of row multiplier pi[p] in solution to the original problem
316 * is the same as in solution to the transformed problem.
318 * 1. In solution to the transformed problem row p and column q cannot
319 * be basic at the same time; otherwise the basis matrix would have
320 * two linear dependent columns: unity column of auxiliary variable
321 * of row p and unity column of variable s.
323 * 2. Though in the transformed problem row p is equality constraint,
324 * it may be basic due to primal degeneracy.
326 * RECOVERING INTERIOR-POINT SOLUTION
328 * Value of row multiplier pi[p] in solution to the original problem
329 * is the same as in solution to the transformed problem.
331 * RECOVERING MIP SOLUTION
335 static int rcv_leq_row(NPP *npp, void *info);
337 void npp_leq_row(NPP *npp, NPPROW *p)
338 { /* process row of 'not greater than' type */
339 struct ineq_row *info;
341 /* the row must have upper bound */
342 xassert(p->ub != +DBL_MAX);
343 xassert(p->lb < p->ub);
344 /* create column for slack variable */
345 s = npp_add_col(npp);
347 s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
348 /* and add it to the transformed problem */
349 npp_add_aij(npp, p, s, +1.0);
350 /* create transformation stack entry */
351 info = npp_push_tse(npp,
352 rcv_leq_row, sizeof(struct ineq_row));
355 /* replace the row by equality constraint */
360 static int rcv_leq_row(NPP *npp, void *_info)
361 { /* recover row of 'not greater than' type */
362 struct ineq_row *info = _info;
363 if (npp->sol == GLP_SOL)
364 { if (npp->r_stat[info->p] == GLP_BS)
365 { if (npp->c_stat[info->s] == GLP_BS)
369 else if (npp->c_stat[info->s] == GLP_NL ||
370 npp->c_stat[info->s] == GLP_NU)
371 npp->r_stat[info->p] = GLP_BS;
377 else if (npp->r_stat[info->p] == GLP_NS)
378 { if (npp->c_stat[info->s] == GLP_BS)
379 npp->r_stat[info->p] = GLP_BS;
380 else if (npp->c_stat[info->s] == GLP_NL)
381 npp->r_stat[info->p] = GLP_NU;
382 else if (npp->c_stat[info->s] == GLP_NU)
383 npp->r_stat[info->p] = GLP_NL;
397 /***********************************************************************
400 * npp_free_col - process free (unbounded) column
404 * #include "glpnpp.h"
405 * void npp_free_col(NPP *npp, NPPCOL *q);
409 * The routine npp_free_col processes column q, which is free (i.e. has
412 * -oo < x[q] < +oo. (1)
414 * PROBLEM TRANSFORMATION
416 * Free (unbounded) variable can be replaced by the difference of two
417 * non-negative variables:
419 * x[q] = s' - s'', s', s'' >= 0. (2)
421 * Assuming that in the transformed problem x[q] becomes s',
422 * transformation (2) causes new column s'' to appear, which differs
423 * from column s' only in the sign of coefficients in constraint and
424 * objective rows. Thus, if in the dual system the following row
425 * corresponds to column s':
427 * sum a[i,q] pi[i] + lambda' = c[q], (3)
430 * the row which corresponds to column s'' is the following:
432 * sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4)
435 * Then from (3) and (4) it follows that:
437 * lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5)
439 * where lambda' and lambda'' are multipliers for columns s' and s'',
442 * RECOVERING BASIC SOLUTION
444 * With respect to (5) status of column q in solution to the original
445 * problem is determined by statuses of columns s' and s'' in solution
446 * to the transformed problem as follows:
448 * +--------------------------------------+------------------+
449 * | Transformed problem | Original problem |
450 * +------------------+-------------------+------------------+
451 * | Status of col s' | Status of col s'' | Status of col q |
452 * +------------------+-------------------+------------------+
453 * | GLP_BS | GLP_BS | N/A |
454 * | GLP_BS | GLP_NL | GLP_BS |
455 * | GLP_NL | GLP_BS | GLP_BS |
456 * | GLP_NL | GLP_NL | GLP_NF |
457 * +------------------+-------------------+------------------+
459 * Value of column q is computed with formula (2).
461 * 1. In solution to the transformed problem columns s' and s'' cannot
462 * be basic at the same time, because they differ only in the sign,
463 * hence, are linear dependent.
465 * 2. Though column q is free, it can be non-basic due to dual
468 * 3. If column q is integral, columns s' and s'' are also integral.
470 * RECOVERING INTERIOR-POINT SOLUTION
472 * Value of column q is computed with formula (2).
474 * RECOVERING MIP SOLUTION
476 * Value of column q is computed with formula (2). */
479 { /* free (unbounded) column */
481 /* column reference number for variables x[q] and s' */
483 /* column reference number for variable s'' */
486 static int rcv_free_col(NPP *npp, void *info);
488 void npp_free_col(NPP *npp, NPPCOL *q)
489 { /* process free (unbounded) column */
490 struct free_col *info;
493 /* the column must be free */
494 xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
495 /* variable x[q] becomes s' */
496 q->lb = 0.0, q->ub = +DBL_MAX;
497 /* create variable s'' */
498 s = npp_add_col(npp);
499 s->is_int = q->is_int;
500 s->lb = 0.0, s->ub = +DBL_MAX;
501 /* duplicate objective coefficient */
503 /* duplicate column of the constraint matrix */
504 for (aij = q->ptr; aij != NULL; aij = aij->c_next)
505 npp_add_aij(npp, aij->row, s, -aij->val);
506 /* create transformation stack entry */
507 info = npp_push_tse(npp,
508 rcv_free_col, sizeof(struct free_col));
514 static int rcv_free_col(NPP *npp, void *_info)
515 { /* recover free (unbounded) column */
516 struct free_col *info = _info;
517 if (npp->sol == GLP_SOL)
518 { if (npp->c_stat[info->q] == GLP_BS)
519 { if (npp->c_stat[info->s] == GLP_BS)
523 else if (npp->c_stat[info->s] == GLP_NL)
524 npp->c_stat[info->q] = GLP_BS;
530 else if (npp->c_stat[info->q] == GLP_NL)
531 { if (npp->c_stat[info->s] == GLP_BS)
532 npp->c_stat[info->q] = GLP_BS;
533 else if (npp->c_stat[info->s] == GLP_NL)
534 npp->c_stat[info->q] = GLP_NF;
545 /* compute value of x[q] with formula (2) */
546 npp->c_value[info->q] -= npp->c_value[info->s];
550 /***********************************************************************
553 * npp_lbnd_col - process column with (non-zero) lower bound
557 * #include "glpnpp.h"
558 * void npp_lbnd_col(NPP *npp, NPPCOL *q);
562 * The routine npp_lbnd_col processes column q, which has (non-zero)
565 * l[q] <= x[q] (<= u[q]), (1)
567 * where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
569 * PROBLEM TRANSFORMATION
571 * Column q can be replaced as follows:
573 * x[q] = l[q] + s, (2)
577 * 0 <= s (<= u[q] - l[q]) (3)
579 * is a non-negative variable.
581 * Substituting x[q] from (2) into the objective row, we have:
583 * z = sum c[j] x[j] + c0 =
586 * = sum c[j] x[j] + c[q] x[q] + c0 =
589 * = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
592 * = sum c[j] x[j] + c[q] s + c~0,
596 * c~0 = c0 + c[q] l[q] (4)
598 * is the constant term of the objective in the transformed problem.
599 * Similarly, substituting x[q] into constraint row i, we have:
601 * L[i] <= sum a[i,j] x[j] <= U[i] ==>
604 * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
607 * L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==>
610 * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
615 * L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5)
617 * are lower and upper bounds of row i in the transformed problem,
620 * Transformation (2) does not affect the dual system.
622 * RECOVERING BASIC SOLUTION
624 * Status of column q in solution to the original problem is the same
625 * as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
626 * Value of column q is computed with formula (2).
628 * RECOVERING INTERIOR-POINT SOLUTION
630 * Value of column q is computed with formula (2).
632 * RECOVERING MIP SOLUTION
634 * Value of column q is computed with formula (2). */
637 { /* bounded column */
639 /* column reference number for variables x[q] and s */
641 /* lower/upper bound l[q] or u[q] */
644 static int rcv_lbnd_col(NPP *npp, void *info);
646 void npp_lbnd_col(NPP *npp, NPPCOL *q)
647 { /* process column with (non-zero) lower bound */
648 struct bnd_col *info;
651 /* the column must have non-zero lower bound */
652 xassert(q->lb != 0.0);
653 xassert(q->lb != -DBL_MAX);
654 xassert(q->lb < q->ub);
655 /* create transformation stack entry */
656 info = npp_push_tse(npp,
657 rcv_lbnd_col, sizeof(struct bnd_col));
660 /* substitute x[q] into objective row */
661 npp->c0 += q->coef * q->lb;
662 /* substitute x[q] into constraint rows */
663 for (aij = q->ptr; aij != NULL; aij = aij->c_next)
666 i->ub = (i->lb -= aij->val * q->lb);
668 { if (i->lb != -DBL_MAX)
669 i->lb -= aij->val * q->lb;
670 if (i->ub != +DBL_MAX)
671 i->ub -= aij->val * q->lb;
674 /* column x[q] becomes column s */
675 if (q->ub != +DBL_MAX)
681 static int rcv_lbnd_col(NPP *npp, void *_info)
682 { /* recover column with (non-zero) lower bound */
683 struct bnd_col *info = _info;
684 if (npp->sol == GLP_SOL)
685 { if (npp->c_stat[info->q] == GLP_BS ||
686 npp->c_stat[info->q] == GLP_NL ||
687 npp->c_stat[info->q] == GLP_NU)
688 npp->c_stat[info->q] = npp->c_stat[info->q];
694 /* compute value of x[q] with formula (2) */
695 npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
699 /***********************************************************************
702 * npp_ubnd_col - process column with upper bound
706 * #include "glpnpp.h"
707 * void npp_ubnd_col(NPP *npp, NPPCOL *q);
711 * The routine npp_ubnd_col processes column q, which has upper bound:
713 * (l[q] <=) x[q] <= u[q], (1)
715 * where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
717 * PROBLEM TRANSFORMATION
719 * Column q can be replaced as follows:
721 * x[q] = u[q] - s, (2)
725 * 0 <= s (<= u[q] - l[q]) (3)
727 * is a non-negative variable.
729 * Substituting x[q] from (2) into the objective row, we have:
731 * z = sum c[j] x[j] + c0 =
734 * = sum c[j] x[j] + c[q] x[q] + c0 =
737 * = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
740 * = sum c[j] x[j] - c[q] s + c~0,
744 * c~0 = c0 + c[q] u[q] (4)
746 * is the constant term of the objective in the transformed problem.
747 * Similarly, substituting x[q] into constraint row i, we have:
749 * L[i] <= sum a[i,j] x[j] <= U[i] ==>
752 * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
755 * L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==>
758 * L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
763 * L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5)
765 * are lower and upper bounds of row i in the transformed problem,
768 * Note that in the transformed problem coefficients c[q] and a[i,q]
769 * change their sign. Thus, the row of the dual system corresponding to
772 * sum a[i,q] pi[i] + lambda[q] = c[q] (6)
775 * in the transformed problem becomes the following:
777 * sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7)
782 * lambda[q] = - lambda[s], (8)
784 * where lambda[q] is multiplier for column q, lambda[s] is multiplier
787 * RECOVERING BASIC SOLUTION
789 * With respect to (8) status of column q in solution to the original
790 * problem is determined by status of column s in solution to the
791 * transformed problem as follows:
793 * +-----------------------+--------------------+
794 * | Status of column s | Status of column q |
795 * | (transformed problem) | (original problem) |
796 * +-----------------------+--------------------+
797 * | GLP_BS | GLP_BS |
798 * | GLP_NL | GLP_NU |
799 * | GLP_NU | GLP_NL |
800 * +-----------------------+--------------------+
802 * Value of column q is computed with formula (2).
804 * RECOVERING INTERIOR-POINT SOLUTION
806 * Value of column q is computed with formula (2).
808 * RECOVERING MIP SOLUTION
810 * Value of column q is computed with formula (2). */
812 static int rcv_ubnd_col(NPP *npp, void *info);
814 void npp_ubnd_col(NPP *npp, NPPCOL *q)
815 { /* process column with upper bound */
816 struct bnd_col *info;
819 /* the column must have upper bound */
820 xassert(q->ub != +DBL_MAX);
821 xassert(q->lb < q->ub);
822 /* create transformation stack entry */
823 info = npp_push_tse(npp,
824 rcv_ubnd_col, sizeof(struct bnd_col));
827 /* substitute x[q] into objective row */
828 npp->c0 += q->coef * q->ub;
830 /* substitute x[q] into constraint rows */
831 for (aij = q->ptr; aij != NULL; aij = aij->c_next)
834 i->ub = (i->lb -= aij->val * q->ub);
836 { if (i->lb != -DBL_MAX)
837 i->lb -= aij->val * q->ub;
838 if (i->ub != +DBL_MAX)
839 i->ub -= aij->val * q->ub;
841 aij->val = -aij->val;
843 /* column x[q] becomes column s */
844 if (q->lb != -DBL_MAX)
852 static int rcv_ubnd_col(NPP *npp, void *_info)
853 { /* recover column with upper bound */
854 struct bnd_col *info = _info;
855 if (npp->sol == GLP_BS)
856 { if (npp->c_stat[info->q] == GLP_BS)
857 npp->c_stat[info->q] = GLP_BS;
858 else if (npp->c_stat[info->q] == GLP_NL)
859 npp->c_stat[info->q] = GLP_NU;
860 else if (npp->c_stat[info->q] == GLP_NU)
861 npp->c_stat[info->q] = GLP_NL;
867 /* compute value of x[q] with formula (2) */
868 npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
872 /***********************************************************************
875 * npp_dbnd_col - process non-negative column with upper bound
879 * #include "glpnpp.h"
880 * void npp_dbnd_col(NPP *npp, NPPCOL *q);
884 * The routine npp_dbnd_col processes column q, which is non-negative
885 * and has upper bound:
887 * 0 <= x[q] <= u[q], (1)
891 * PROBLEM TRANSFORMATION
893 * Upper bound of column q can be replaced by the following equality
896 * x[q] + s = u[q], (2)
898 * where s >= 0 is a non-negative complement variable.
900 * Since in the primal system along with new row (2) there appears a
901 * new column s having the only non-zero coefficient in this row, in
902 * the dual system there appears a new row:
904 * (+1)pi + lambda[s] = 0, (3)
906 * where (+1) is coefficient at column s in row (2), pi is multiplier
907 * for row (2), lambda[s] is multiplier for column s, 0 is coefficient
908 * at column s in the objective row.
910 * RECOVERING BASIC SOLUTION
912 * Status of column q in solution to the original problem is determined
913 * by its status and status of column s in solution to the transformed
914 * problem as follows:
916 * +-----------------------------------+------------------+
917 * | Transformed problem | Original problem |
918 * +-----------------+-----------------+------------------+
919 * | Status of col q | Status of col s | Status of col q |
920 * +-----------------+-----------------+------------------+
921 * | GLP_BS | GLP_BS | GLP_BS |
922 * | GLP_BS | GLP_NL | GLP_NU |
923 * | GLP_NL | GLP_BS | GLP_NL |
924 * | GLP_NL | GLP_NL | GLP_NL (*) |
925 * +-----------------+-----------------+------------------+
927 * Value of column q in solution to the original problem is the same as
928 * in solution to the transformed problem.
930 * 1. Formally, in solution to the transformed problem columns q and s
931 * cannot be non-basic at the same time, since the constraint (2)
932 * would be violated. However, if u[q] is close to zero, violation
933 * may be less than a working precision even if both columns q and s
934 * are non-basic. In this degenerate case row (2) can be only basic,
935 * i.e. non-active constraint (otherwise corresponding row of the
936 * basis matrix would be zero). This allows to pivot out auxiliary
937 * variable and pivot in column s, in which case the row becomes
938 * active while column s becomes basic.
940 * 2. If column q is integral, column s is also integral.
942 * RECOVERING INTERIOR-POINT SOLUTION
944 * Value of column q in solution to the original problem is the same as
945 * in solution to the transformed problem.
947 * RECOVERING MIP SOLUTION
949 * Value of column q in solution to the original problem is the same as
950 * in solution to the transformed problem. */
953 { /* double-bounded column */
955 /* column reference number for variable x[q] */
957 /* column reference number for complement variable s */
960 static int rcv_dbnd_col(NPP *npp, void *info);
962 void npp_dbnd_col(NPP *npp, NPPCOL *q)
963 { /* process non-negative column with upper bound */
964 struct dbnd_col *info;
967 /* the column must be non-negative with upper bound */
968 xassert(q->lb == 0.0);
969 xassert(q->ub > 0.0);
970 xassert(q->ub != +DBL_MAX);
971 /* create variable s */
972 s = npp_add_col(npp);
973 s->is_int = q->is_int;
974 s->lb = 0.0, s->ub = +DBL_MAX;
975 /* create equality constraint (2) */
976 p = npp_add_row(npp);
977 p->lb = p->ub = q->ub;
978 npp_add_aij(npp, p, q, +1.0);
979 npp_add_aij(npp, p, s, +1.0);
980 /* create transformation stack entry */
981 info = npp_push_tse(npp,
982 rcv_dbnd_col, sizeof(struct dbnd_col));
985 /* remove upper bound of x[q] */
990 static int rcv_dbnd_col(NPP *npp, void *_info)
991 { /* recover non-negative column with upper bound */
992 struct dbnd_col *info = _info;
993 if (npp->sol == GLP_BS)
994 { if (npp->c_stat[info->q] == GLP_BS)
995 { if (npp->c_stat[info->s] == GLP_BS)
996 npp->c_stat[info->q] = GLP_BS;
997 else if (npp->c_stat[info->s] == GLP_NL)
998 npp->c_stat[info->q] = GLP_NU;
1004 else if (npp->c_stat[info->q] == GLP_NL)
1005 { if (npp->c_stat[info->s] == GLP_BS ||
1006 npp->c_stat[info->s] == GLP_NL)
1007 npp->c_stat[info->q] = GLP_NL;
1021 /***********************************************************************
1024 * npp_fixed_col - process fixed column
1028 * #include "glpnpp.h"
1029 * void npp_fixed_col(NPP *npp, NPPCOL *q);
1033 * The routine npp_fixed_col processes column q, which is fixed:
1037 * where s[q] is a fixed column value.
1039 * PROBLEM TRANSFORMATION
1041 * The value of a fixed column can be substituted into the objective
1042 * and constraint rows that allows removing the column from the problem.
1044 * Substituting x[q] = s[q] into the objective row, we have:
1046 * z = sum c[j] x[j] + c0 =
1049 * = sum c[j] x[j] + c[q] x[q] + c0 =
1052 * = sum c[j] x[j] + c[q] s[q] + c0 =
1055 * = sum c[j] x[j] + c~0,
1060 * c~0 = c0 + c[q] s[q] (2)
1062 * is the constant term of the objective in the transformed problem.
1063 * Similarly, substituting x[q] = s[q] into constraint row i, we have:
1065 * L[i] <= sum a[i,j] x[j] <= U[i] ==>
1068 * L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==>
1071 * L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==>
1074 * L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
1079 * L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3)
1081 * are lower and upper bounds of row i in the transformed problem,
1084 * RECOVERING BASIC SOLUTION
1086 * Column q is assigned status GLP_NS and its value is assigned s[q].
1088 * RECOVERING INTERIOR-POINT SOLUTION
1090 * Value of column q is assigned s[q].
1092 * RECOVERING MIP SOLUTION
1094 * Value of column q is assigned s[q]. */
1097 { /* fixed column */
1099 /* column reference number for variable x[q] */
1101 /* value, at which x[q] is fixed */
1104 static int rcv_fixed_col(NPP *npp, void *info);
1106 void npp_fixed_col(NPP *npp, NPPCOL *q)
1107 { /* process fixed column */
1108 struct fixed_col *info;
1111 /* the column must be fixed */
1112 xassert(q->lb == q->ub);
1113 /* create transformation stack entry */
1114 info = npp_push_tse(npp,
1115 rcv_fixed_col, sizeof(struct fixed_col));
1118 /* substitute x[q] = s[q] into objective row */
1119 npp->c0 += q->coef * q->lb;
1120 /* substitute x[q] = s[q] into constraint rows */
1121 for (aij = q->ptr; aij != NULL; aij = aij->c_next)
1124 i->ub = (i->lb -= aij->val * q->lb);
1126 { if (i->lb != -DBL_MAX)
1127 i->lb -= aij->val * q->lb;
1128 if (i->ub != +DBL_MAX)
1129 i->ub -= aij->val * q->lb;
1132 /* remove the column from the problem */
1133 npp_del_col(npp, q);
1137 static int rcv_fixed_col(NPP *npp, void *_info)
1138 { /* recover fixed column */
1139 struct fixed_col *info = _info;
1140 if (npp->sol == GLP_SOL)
1141 npp->c_stat[info->q] = GLP_NS;
1142 npp->c_value[info->q] = info->s;
1146 /***********************************************************************
1149 * npp_make_equality - process row with almost identical bounds
1153 * #include "glpnpp.h"
1154 * int npp_make_equality(NPP *npp, NPPROW *p);
1158 * The routine npp_make_equality processes row p:
1160 * L[p] <= sum a[p,j] x[j] <= U[p], (1)
1163 * where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
1168 * 0 - row bounds have not been changed;
1170 * 1 - row has been replaced by equality constraint.
1172 * PROBLEM TRANSFORMATION
1174 * If bounds of row (1) are very close to each other:
1176 * U[p] - L[p] <= eps, (2)
1178 * where eps is an absolute tolerance for row value, the row can be
1179 * replaced by the following almost equivalent equiality constraint:
1181 * sum a[p,j] x[j] = b, (3)
1184 * where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
1185 * to be very close to its nearest integer:
1187 * |b - floor(b + 0.5)| <= eps, (4)
1189 * it is reasonable to use this nearest integer as the right-hand side.
1191 * RECOVERING BASIC SOLUTION
1193 * Status of row p in solution to the original problem is determined
1194 * by its status and the sign of its multiplier pi[p] in solution to
1195 * the transformed problem as follows:
1197 * +-----------------------+---------+--------------------+
1198 * | Status of row p | Sign of | Status of row p |
1199 * | (transformed problem) | pi[p] | (original problem) |
1200 * +-----------------------+---------+--------------------+
1201 * | GLP_BS | + / - | GLP_BS |
1202 * | GLP_NS | + | GLP_NL |
1203 * | GLP_NS | - | GLP_NU |
1204 * +-----------------------+---------+--------------------+
1206 * Value of row multiplier pi[p] in solution to the original problem is
1207 * the same as in solution to the transformed problem.
1209 * RECOVERING INTERIOR POINT SOLUTION
1211 * Value of row multiplier pi[p] in solution to the original problem is
1212 * the same as in solution to the transformed problem.
1214 * RECOVERING MIP SOLUTION
1218 struct make_equality
1219 { /* row with almost identical bounds */
1221 /* row reference number */
1224 static int rcv_make_equality(NPP *npp, void *info);
1226 int npp_make_equality(NPP *npp, NPPROW *p)
1227 { /* process row with almost identical bounds */
1228 struct make_equality *info;
1229 double b, eps, nint;
1230 /* the row must be double-sided inequality */
1231 xassert(p->lb != -DBL_MAX);
1232 xassert(p->ub != +DBL_MAX);
1233 xassert(p->lb < p->ub);
1234 /* check row bounds */
1235 eps = 1e-9 + 1e-12 * fabs(p->lb);
1236 if (p->ub - p->lb > eps) return 0;
1237 /* row bounds are very close to each other */
1238 /* create transformation stack entry */
1239 info = npp_push_tse(npp,
1240 rcv_make_equality, sizeof(struct make_equality));
1242 /* compute right-hand side */
1243 b = 0.5 * (p->ub + p->lb);
1244 nint = floor(b + 0.5);
1245 if (fabs(b - nint) <= eps) b = nint;
1246 /* replace row p by almost equivalent equality constraint */
1251 int rcv_make_equality(NPP *npp, void *_info)
1252 { /* recover row with almost identical bounds */
1253 struct make_equality *info = _info;
1254 if (npp->sol == GLP_SOL)
1255 { if (npp->r_stat[info->p] == GLP_BS)
1256 npp->r_stat[info->p] = GLP_BS;
1257 else if (npp->r_stat[info->p] == GLP_NS)
1258 { if (npp->r_pi[info->p] >= 0.0)
1259 npp->r_stat[info->p] = GLP_NL;
1261 npp->r_stat[info->p] = GLP_NU;
1271 /***********************************************************************
1274 * npp_make_fixed - process column with almost identical bounds
1278 * #include "glpnpp.h"
1279 * int npp_make_fixed(NPP *npp, NPPCOL *q);
1283 * The routine npp_make_fixed processes column q:
1285 * l[q] <= x[q] <= u[q], (1)
1287 * where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
1292 * 0 - column bounds have not been changed;
1294 * 1 - column has been fixed.
1296 * PROBLEM TRANSFORMATION
1298 * If bounds of column (1) are very close to each other:
1300 * u[q] - l[q] <= eps, (2)
1302 * where eps is an absolute tolerance for column value, the column can
1307 * where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
1308 * happens to be very close to its nearest integer:
1310 * |s[q] - floor(s[q] + 0.5)| <= eps, (4)
1312 * it is reasonable to use this nearest integer as the fixed value.
1314 * RECOVERING BASIC SOLUTION
1316 * In the dual system of the original (as well as transformed) problem
1317 * column q corresponds to the following row:
1319 * sum a[i,q] pi[i] + lambda[q] = c[q]. (5)
1322 * Since multipliers pi[i] are known for all rows from solution to the
1323 * transformed problem, formula (5) allows computing value of multiplier
1324 * (reduced cost) for column q:
1326 * lambda[q] = c[q] - sum a[i,q] pi[i]. (6)
1329 * Status of column q in solution to the original problem is determined
1330 * by its status and the sign of its multiplier lambda[q] in solution to
1331 * the transformed problem as follows:
1333 * +-----------------------+-----------+--------------------+
1334 * | Status of column q | Sign of | Status of column q |
1335 * | (transformed problem) | lambda[q] | (original problem) |
1336 * +-----------------------+-----------+--------------------+
1337 * | GLP_BS | + / - | GLP_BS |
1338 * | GLP_NS | + | GLP_NL |
1339 * | GLP_NS | - | GLP_NU |
1340 * +-----------------------+-----------+--------------------+
1342 * Value of column q in solution to the original problem is the same as
1343 * in solution to the transformed problem.
1345 * RECOVERING INTERIOR POINT SOLUTION
1347 * Value of column q in solution to the original problem is the same as
1348 * in solution to the transformed problem.
1350 * RECOVERING MIP SOLUTION
1355 { /* column with almost identical bounds */
1357 /* column reference number */
1359 /* objective coefficient at x[q] */
1361 /* list of non-zero coefficients a[i,q] */
1364 static int rcv_make_fixed(NPP *npp, void *info);
1366 int npp_make_fixed(NPP *npp, NPPCOL *q)
1367 { /* process column with almost identical bounds */
1368 struct make_fixed *info;
1371 double s, eps, nint;
1372 /* the column must be double-bounded */
1373 xassert(q->lb != -DBL_MAX);
1374 xassert(q->ub != +DBL_MAX);
1375 xassert(q->lb < q->ub);
1376 /* check column bounds */
1377 eps = 1e-9 + 1e-12 * fabs(q->lb);
1378 if (q->ub - q->lb > eps) return 0;
1379 /* column bounds are very close to each other */
1380 /* create transformation stack entry */
1381 info = npp_push_tse(npp,
1382 rcv_make_fixed, sizeof(struct make_fixed));
1386 /* save column coefficients a[i,q] (needed for basic solution
1388 if (npp->sol == GLP_SOL)
1389 { for (aij = q->ptr; aij != NULL; aij = aij->c_next)
1390 { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
1391 lfe->ref = aij->row->i;
1392 lfe->val = aij->val;
1393 lfe->next = info->ptr;
1397 /* compute column fixed value */
1398 s = 0.5 * (q->ub + q->lb);
1399 nint = floor(s + 0.5);
1400 if (fabs(s - nint) <= eps) s = nint;
1401 /* make column q fixed */
1406 static int rcv_make_fixed(NPP *npp, void *_info)
1407 { /* recover column with almost identical bounds */
1408 struct make_fixed *info = _info;
1411 if (npp->sol == GLP_SOL)
1412 { if (npp->c_stat[info->q] == GLP_BS)
1413 npp->c_stat[info->q] = GLP_BS;
1414 else if (npp->c_stat[info->q] == GLP_NS)
1415 { /* compute multiplier for column q with formula (6) */
1417 for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
1418 lambda -= lfe->val * npp->r_pi[lfe->ref];
1419 /* assign status to non-basic column */
1421 npp->c_stat[info->q] = GLP_NL;
1423 npp->c_stat[info->q] = GLP_NU;