lemon-project-template-glpk
diff deps/glpk/src/glpnpp02.c @ 9:33de93886c88
Import GLPK 4.47
author | Alpar Juttner <alpar@cs.elte.hu> |
---|---|
date | Sun, 06 Nov 2011 20:59:10 +0100 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/deps/glpk/src/glpnpp02.c Sun Nov 06 20:59:10 2011 +0100 1.3 @@ -0,0 +1,1433 @@ 1.4 +/* glpnpp02.c */ 1.5 + 1.6 +/*********************************************************************** 1.7 +* This code is part of GLPK (GNU Linear Programming Kit). 1.8 +* 1.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 1.10 +* 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, 1.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved. 1.12 +* E-mail: <mao@gnu.org>. 1.13 +* 1.14 +* GLPK is free software: you can redistribute it and/or modify it 1.15 +* under the terms of the GNU General Public License as published by 1.16 +* the Free Software Foundation, either version 3 of the License, or 1.17 +* (at your option) any later version. 1.18 +* 1.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT 1.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1.22 +* License for more details. 1.23 +* 1.24 +* You should have received a copy of the GNU General Public License 1.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. 1.26 +***********************************************************************/ 1.27 + 1.28 +#include "glpnpp.h" 1.29 + 1.30 +/*********************************************************************** 1.31 +* NAME 1.32 +* 1.33 +* npp_free_row - process free (unbounded) row 1.34 +* 1.35 +* SYNOPSIS 1.36 +* 1.37 +* #include "glpnpp.h" 1.38 +* void npp_free_row(NPP *npp, NPPROW *p); 1.39 +* 1.40 +* DESCRIPTION 1.41 +* 1.42 +* The routine npp_free_row processes row p, which is free (i.e. has 1.43 +* no finite bounds): 1.44 +* 1.45 +* -inf < sum a[p,j] x[j] < +inf. (1) 1.46 +* j 1.47 +* 1.48 +* PROBLEM TRANSFORMATION 1.49 +* 1.50 +* Constraint (1) cannot be active, so it is redundant and can be 1.51 +* removed from the original problem. 1.52 +* 1.53 +* Removing row p leads to removing a column of multiplier pi[p] for 1.54 +* this row in the dual system. Since row p has no bounds, pi[p] = 0, 1.55 +* so removing the column does not affect the dual solution. 1.56 +* 1.57 +* RECOVERING BASIC SOLUTION 1.58 +* 1.59 +* In solution to the original problem row p is inactive constraint, 1.60 +* so it is assigned status GLP_BS, and multiplier pi[p] is assigned 1.61 +* zero value. 1.62 +* 1.63 +* RECOVERING INTERIOR-POINT SOLUTION 1.64 +* 1.65 +* In solution to the original problem row p is inactive constraint, 1.66 +* so its multiplier pi[p] is assigned zero value. 1.67 +* 1.68 +* RECOVERING MIP SOLUTION 1.69 +* 1.70 +* None needed. */ 1.71 + 1.72 +struct free_row 1.73 +{ /* free (unbounded) row */ 1.74 + int p; 1.75 + /* row reference number */ 1.76 +}; 1.77 + 1.78 +static int rcv_free_row(NPP *npp, void *info); 1.79 + 1.80 +void npp_free_row(NPP *npp, NPPROW *p) 1.81 +{ /* process free (unbounded) row */ 1.82 + struct free_row *info; 1.83 + /* the row must be free */ 1.84 + xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX); 1.85 + /* create transformation stack entry */ 1.86 + info = npp_push_tse(npp, 1.87 + rcv_free_row, sizeof(struct free_row)); 1.88 + info->p = p->i; 1.89 + /* remove the row from the problem */ 1.90 + npp_del_row(npp, p); 1.91 + return; 1.92 +} 1.93 + 1.94 +static int rcv_free_row(NPP *npp, void *_info) 1.95 +{ /* recover free (unbounded) row */ 1.96 + struct free_row *info = _info; 1.97 + if (npp->sol == GLP_SOL) 1.98 + npp->r_stat[info->p] = GLP_BS; 1.99 + if (npp->sol != GLP_MIP) 1.100 + npp->r_pi[info->p] = 0.0; 1.101 + return 0; 1.102 +} 1.103 + 1.104 +/*********************************************************************** 1.105 +* NAME 1.106 +* 1.107 +* npp_geq_row - process row of 'not less than' type 1.108 +* 1.109 +* SYNOPSIS 1.110 +* 1.111 +* #include "glpnpp.h" 1.112 +* void npp_geq_row(NPP *npp, NPPROW *p); 1.113 +* 1.114 +* DESCRIPTION 1.115 +* 1.116 +* The routine npp_geq_row processes row p, which is 'not less than' 1.117 +* inequality constraint: 1.118 +* 1.119 +* L[p] <= sum a[p,j] x[j] (<= U[p]), (1) 1.120 +* j 1.121 +* 1.122 +* where L[p] < U[p], and upper bound may not exist (U[p] = +oo). 1.123 +* 1.124 +* PROBLEM TRANSFORMATION 1.125 +* 1.126 +* Constraint (1) can be replaced by equality constraint: 1.127 +* 1.128 +* sum a[p,j] x[j] - s = L[p], (2) 1.129 +* j 1.130 +* 1.131 +* where 1.132 +* 1.133 +* 0 <= s (<= U[p] - L[p]) (3) 1.134 +* 1.135 +* is a non-negative surplus variable. 1.136 +* 1.137 +* Since in the primal system there appears column s having the only 1.138 +* non-zero coefficient in row p, in the dual system there appears a 1.139 +* new row: 1.140 +* 1.141 +* (-1) pi[p] + lambda = 0, (4) 1.142 +* 1.143 +* where (-1) is coefficient of column s in row p, pi[p] is multiplier 1.144 +* of row p, lambda is multiplier of column q, 0 is coefficient of 1.145 +* column s in the objective row. 1.146 +* 1.147 +* RECOVERING BASIC SOLUTION 1.148 +* 1.149 +* Status of row p in solution to the original problem is determined 1.150 +* by its status and status of column q in solution to the transformed 1.151 +* problem as follows: 1.152 +* 1.153 +* +--------------------------------------+------------------+ 1.154 +* | Transformed problem | Original problem | 1.155 +* +-----------------+--------------------+------------------+ 1.156 +* | Status of row p | Status of column s | Status of row p | 1.157 +* +-----------------+--------------------+------------------+ 1.158 +* | GLP_BS | GLP_BS | N/A | 1.159 +* | GLP_BS | GLP_NL | GLP_BS | 1.160 +* | GLP_BS | GLP_NU | GLP_BS | 1.161 +* | GLP_NS | GLP_BS | GLP_BS | 1.162 +* | GLP_NS | GLP_NL | GLP_NL | 1.163 +* | GLP_NS | GLP_NU | GLP_NU | 1.164 +* +-----------------+--------------------+------------------+ 1.165 +* 1.166 +* Value of row multiplier pi[p] in solution to the original problem 1.167 +* is the same as in solution to the transformed problem. 1.168 +* 1.169 +* 1. In solution to the transformed problem row p and column q cannot 1.170 +* be basic at the same time; otherwise the basis matrix would have 1.171 +* two linear dependent columns: unity column of auxiliary variable 1.172 +* of row p and unity column of variable s. 1.173 +* 1.174 +* 2. Though in the transformed problem row p is equality constraint, 1.175 +* it may be basic due to primal degenerate solution. 1.176 +* 1.177 +* RECOVERING INTERIOR-POINT SOLUTION 1.178 +* 1.179 +* Value of row multiplier pi[p] in solution to the original problem 1.180 +* is the same as in solution to the transformed problem. 1.181 +* 1.182 +* RECOVERING MIP SOLUTION 1.183 +* 1.184 +* None needed. */ 1.185 + 1.186 +struct ineq_row 1.187 +{ /* inequality constraint row */ 1.188 + int p; 1.189 + /* row reference number */ 1.190 + int s; 1.191 + /* column reference number for slack/surplus variable */ 1.192 +}; 1.193 + 1.194 +static int rcv_geq_row(NPP *npp, void *info); 1.195 + 1.196 +void npp_geq_row(NPP *npp, NPPROW *p) 1.197 +{ /* process row of 'not less than' type */ 1.198 + struct ineq_row *info; 1.199 + NPPCOL *s; 1.200 + /* the row must have lower bound */ 1.201 + xassert(p->lb != -DBL_MAX); 1.202 + xassert(p->lb < p->ub); 1.203 + /* create column for surplus variable */ 1.204 + s = npp_add_col(npp); 1.205 + s->lb = 0.0; 1.206 + s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb); 1.207 + /* and add it to the transformed problem */ 1.208 + npp_add_aij(npp, p, s, -1.0); 1.209 + /* create transformation stack entry */ 1.210 + info = npp_push_tse(npp, 1.211 + rcv_geq_row, sizeof(struct ineq_row)); 1.212 + info->p = p->i; 1.213 + info->s = s->j; 1.214 + /* replace the row by equality constraint */ 1.215 + p->ub = p->lb; 1.216 + return; 1.217 +} 1.218 + 1.219 +static int rcv_geq_row(NPP *npp, void *_info) 1.220 +{ /* recover row of 'not less than' type */ 1.221 + struct ineq_row *info = _info; 1.222 + if (npp->sol == GLP_SOL) 1.223 + { if (npp->r_stat[info->p] == GLP_BS) 1.224 + { if (npp->c_stat[info->s] == GLP_BS) 1.225 + { npp_error(); 1.226 + return 1; 1.227 + } 1.228 + else if (npp->c_stat[info->s] == GLP_NL || 1.229 + npp->c_stat[info->s] == GLP_NU) 1.230 + npp->r_stat[info->p] = GLP_BS; 1.231 + else 1.232 + { npp_error(); 1.233 + return 1; 1.234 + } 1.235 + } 1.236 + else if (npp->r_stat[info->p] == GLP_NS) 1.237 + { if (npp->c_stat[info->s] == GLP_BS) 1.238 + npp->r_stat[info->p] = GLP_BS; 1.239 + else if (npp->c_stat[info->s] == GLP_NL) 1.240 + npp->r_stat[info->p] = GLP_NL; 1.241 + else if (npp->c_stat[info->s] == GLP_NU) 1.242 + npp->r_stat[info->p] = GLP_NU; 1.243 + else 1.244 + { npp_error(); 1.245 + return 1; 1.246 + } 1.247 + } 1.248 + else 1.249 + { npp_error(); 1.250 + return 1; 1.251 + } 1.252 + } 1.253 + return 0; 1.254 +} 1.255 + 1.256 +/*********************************************************************** 1.257 +* NAME 1.258 +* 1.259 +* npp_leq_row - process row of 'not greater than' type 1.260 +* 1.261 +* SYNOPSIS 1.262 +* 1.263 +* #include "glpnpp.h" 1.264 +* void npp_leq_row(NPP *npp, NPPROW *p); 1.265 +* 1.266 +* DESCRIPTION 1.267 +* 1.268 +* The routine npp_leq_row processes row p, which is 'not greater than' 1.269 +* inequality constraint: 1.270 +* 1.271 +* (L[p] <=) sum a[p,j] x[j] <= U[p], (1) 1.272 +* j 1.273 +* 1.274 +* where L[p] < U[p], and lower bound may not exist (L[p] = +oo). 1.275 +* 1.276 +* PROBLEM TRANSFORMATION 1.277 +* 1.278 +* Constraint (1) can be replaced by equality constraint: 1.279 +* 1.280 +* sum a[p,j] x[j] + s = L[p], (2) 1.281 +* j 1.282 +* 1.283 +* where 1.284 +* 1.285 +* 0 <= s (<= U[p] - L[p]) (3) 1.286 +* 1.287 +* is a non-negative slack variable. 1.288 +* 1.289 +* Since in the primal system there appears column s having the only 1.290 +* non-zero coefficient in row p, in the dual system there appears a 1.291 +* new row: 1.292 +* 1.293 +* (+1) pi[p] + lambda = 0, (4) 1.294 +* 1.295 +* where (+1) is coefficient of column s in row p, pi[p] is multiplier 1.296 +* of row p, lambda is multiplier of column q, 0 is coefficient of 1.297 +* column s in the objective row. 1.298 +* 1.299 +* RECOVERING BASIC SOLUTION 1.300 +* 1.301 +* Status of row p in solution to the original problem is determined 1.302 +* by its status and status of column q in solution to the transformed 1.303 +* problem as follows: 1.304 +* 1.305 +* +--------------------------------------+------------------+ 1.306 +* | Transformed problem | Original problem | 1.307 +* +-----------------+--------------------+------------------+ 1.308 +* | Status of row p | Status of column s | Status of row p | 1.309 +* +-----------------+--------------------+------------------+ 1.310 +* | GLP_BS | GLP_BS | N/A | 1.311 +* | GLP_BS | GLP_NL | GLP_BS | 1.312 +* | GLP_BS | GLP_NU | GLP_BS | 1.313 +* | GLP_NS | GLP_BS | GLP_BS | 1.314 +* | GLP_NS | GLP_NL | GLP_NU | 1.315 +* | GLP_NS | GLP_NU | GLP_NL | 1.316 +* +-----------------+--------------------+------------------+ 1.317 +* 1.318 +* Value of row multiplier pi[p] in solution to the original problem 1.319 +* is the same as in solution to the transformed problem. 1.320 +* 1.321 +* 1. In solution to the transformed problem row p and column q cannot 1.322 +* be basic at the same time; otherwise the basis matrix would have 1.323 +* two linear dependent columns: unity column of auxiliary variable 1.324 +* of row p and unity column of variable s. 1.325 +* 1.326 +* 2. Though in the transformed problem row p is equality constraint, 1.327 +* it may be basic due to primal degeneracy. 1.328 +* 1.329 +* RECOVERING INTERIOR-POINT SOLUTION 1.330 +* 1.331 +* Value of row multiplier pi[p] in solution to the original problem 1.332 +* is the same as in solution to the transformed problem. 1.333 +* 1.334 +* RECOVERING MIP SOLUTION 1.335 +* 1.336 +* None needed. */ 1.337 + 1.338 +static int rcv_leq_row(NPP *npp, void *info); 1.339 + 1.340 +void npp_leq_row(NPP *npp, NPPROW *p) 1.341 +{ /* process row of 'not greater than' type */ 1.342 + struct ineq_row *info; 1.343 + NPPCOL *s; 1.344 + /* the row must have upper bound */ 1.345 + xassert(p->ub != +DBL_MAX); 1.346 + xassert(p->lb < p->ub); 1.347 + /* create column for slack variable */ 1.348 + s = npp_add_col(npp); 1.349 + s->lb = 0.0; 1.350 + s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb); 1.351 + /* and add it to the transformed problem */ 1.352 + npp_add_aij(npp, p, s, +1.0); 1.353 + /* create transformation stack entry */ 1.354 + info = npp_push_tse(npp, 1.355 + rcv_leq_row, sizeof(struct ineq_row)); 1.356 + info->p = p->i; 1.357 + info->s = s->j; 1.358 + /* replace the row by equality constraint */ 1.359 + p->lb = p->ub; 1.360 + return; 1.361 +} 1.362 + 1.363 +static int rcv_leq_row(NPP *npp, void *_info) 1.364 +{ /* recover row of 'not greater than' type */ 1.365 + struct ineq_row *info = _info; 1.366 + if (npp->sol == GLP_SOL) 1.367 + { if (npp->r_stat[info->p] == GLP_BS) 1.368 + { if (npp->c_stat[info->s] == GLP_BS) 1.369 + { npp_error(); 1.370 + return 1; 1.371 + } 1.372 + else if (npp->c_stat[info->s] == GLP_NL || 1.373 + npp->c_stat[info->s] == GLP_NU) 1.374 + npp->r_stat[info->p] = GLP_BS; 1.375 + else 1.376 + { npp_error(); 1.377 + return 1; 1.378 + } 1.379 + } 1.380 + else if (npp->r_stat[info->p] == GLP_NS) 1.381 + { if (npp->c_stat[info->s] == GLP_BS) 1.382 + npp->r_stat[info->p] = GLP_BS; 1.383 + else if (npp->c_stat[info->s] == GLP_NL) 1.384 + npp->r_stat[info->p] = GLP_NU; 1.385 + else if (npp->c_stat[info->s] == GLP_NU) 1.386 + npp->r_stat[info->p] = GLP_NL; 1.387 + else 1.388 + { npp_error(); 1.389 + return 1; 1.390 + } 1.391 + } 1.392 + else 1.393 + { npp_error(); 1.394 + return 1; 1.395 + } 1.396 + } 1.397 + return 0; 1.398 +} 1.399 + 1.400 +/*********************************************************************** 1.401 +* NAME 1.402 +* 1.403 +* npp_free_col - process free (unbounded) column 1.404 +* 1.405 +* SYNOPSIS 1.406 +* 1.407 +* #include "glpnpp.h" 1.408 +* void npp_free_col(NPP *npp, NPPCOL *q); 1.409 +* 1.410 +* DESCRIPTION 1.411 +* 1.412 +* The routine npp_free_col processes column q, which is free (i.e. has 1.413 +* no finite bounds): 1.414 +* 1.415 +* -oo < x[q] < +oo. (1) 1.416 +* 1.417 +* PROBLEM TRANSFORMATION 1.418 +* 1.419 +* Free (unbounded) variable can be replaced by the difference of two 1.420 +* non-negative variables: 1.421 +* 1.422 +* x[q] = s' - s'', s', s'' >= 0. (2) 1.423 +* 1.424 +* Assuming that in the transformed problem x[q] becomes s', 1.425 +* transformation (2) causes new column s'' to appear, which differs 1.426 +* from column s' only in the sign of coefficients in constraint and 1.427 +* objective rows. Thus, if in the dual system the following row 1.428 +* corresponds to column s': 1.429 +* 1.430 +* sum a[i,q] pi[i] + lambda' = c[q], (3) 1.431 +* i 1.432 +* 1.433 +* the row which corresponds to column s'' is the following: 1.434 +* 1.435 +* sum (-a[i,q]) pi[i] + lambda'' = -c[q]. (4) 1.436 +* i 1.437 +* 1.438 +* Then from (3) and (4) it follows that: 1.439 +* 1.440 +* lambda' + lambda'' = 0 => lambda' = lmabda'' = 0, (5) 1.441 +* 1.442 +* where lambda' and lambda'' are multipliers for columns s' and s'', 1.443 +* resp. 1.444 +* 1.445 +* RECOVERING BASIC SOLUTION 1.446 +* 1.447 +* With respect to (5) status of column q in solution to the original 1.448 +* problem is determined by statuses of columns s' and s'' in solution 1.449 +* to the transformed problem as follows: 1.450 +* 1.451 +* +--------------------------------------+------------------+ 1.452 +* | Transformed problem | Original problem | 1.453 +* +------------------+-------------------+------------------+ 1.454 +* | Status of col s' | Status of col s'' | Status of col q | 1.455 +* +------------------+-------------------+------------------+ 1.456 +* | GLP_BS | GLP_BS | N/A | 1.457 +* | GLP_BS | GLP_NL | GLP_BS | 1.458 +* | GLP_NL | GLP_BS | GLP_BS | 1.459 +* | GLP_NL | GLP_NL | GLP_NF | 1.460 +* +------------------+-------------------+------------------+ 1.461 +* 1.462 +* Value of column q is computed with formula (2). 1.463 +* 1.464 +* 1. In solution to the transformed problem columns s' and s'' cannot 1.465 +* be basic at the same time, because they differ only in the sign, 1.466 +* hence, are linear dependent. 1.467 +* 1.468 +* 2. Though column q is free, it can be non-basic due to dual 1.469 +* degeneracy. 1.470 +* 1.471 +* 3. If column q is integral, columns s' and s'' are also integral. 1.472 +* 1.473 +* RECOVERING INTERIOR-POINT SOLUTION 1.474 +* 1.475 +* Value of column q is computed with formula (2). 1.476 +* 1.477 +* RECOVERING MIP SOLUTION 1.478 +* 1.479 +* Value of column q is computed with formula (2). */ 1.480 + 1.481 +struct free_col 1.482 +{ /* free (unbounded) column */ 1.483 + int q; 1.484 + /* column reference number for variables x[q] and s' */ 1.485 + int s; 1.486 + /* column reference number for variable s'' */ 1.487 +}; 1.488 + 1.489 +static int rcv_free_col(NPP *npp, void *info); 1.490 + 1.491 +void npp_free_col(NPP *npp, NPPCOL *q) 1.492 +{ /* process free (unbounded) column */ 1.493 + struct free_col *info; 1.494 + NPPCOL *s; 1.495 + NPPAIJ *aij; 1.496 + /* the column must be free */ 1.497 + xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX); 1.498 + /* variable x[q] becomes s' */ 1.499 + q->lb = 0.0, q->ub = +DBL_MAX; 1.500 + /* create variable s'' */ 1.501 + s = npp_add_col(npp); 1.502 + s->is_int = q->is_int; 1.503 + s->lb = 0.0, s->ub = +DBL_MAX; 1.504 + /* duplicate objective coefficient */ 1.505 + s->coef = -q->coef; 1.506 + /* duplicate column of the constraint matrix */ 1.507 + for (aij = q->ptr; aij != NULL; aij = aij->c_next) 1.508 + npp_add_aij(npp, aij->row, s, -aij->val); 1.509 + /* create transformation stack entry */ 1.510 + info = npp_push_tse(npp, 1.511 + rcv_free_col, sizeof(struct free_col)); 1.512 + info->q = q->j; 1.513 + info->s = s->j; 1.514 + return; 1.515 +} 1.516 + 1.517 +static int rcv_free_col(NPP *npp, void *_info) 1.518 +{ /* recover free (unbounded) column */ 1.519 + struct free_col *info = _info; 1.520 + if (npp->sol == GLP_SOL) 1.521 + { if (npp->c_stat[info->q] == GLP_BS) 1.522 + { if (npp->c_stat[info->s] == GLP_BS) 1.523 + { npp_error(); 1.524 + return 1; 1.525 + } 1.526 + else if (npp->c_stat[info->s] == GLP_NL) 1.527 + npp->c_stat[info->q] = GLP_BS; 1.528 + else 1.529 + { npp_error(); 1.530 + return -1; 1.531 + } 1.532 + } 1.533 + else if (npp->c_stat[info->q] == GLP_NL) 1.534 + { if (npp->c_stat[info->s] == GLP_BS) 1.535 + npp->c_stat[info->q] = GLP_BS; 1.536 + else if (npp->c_stat[info->s] == GLP_NL) 1.537 + npp->c_stat[info->q] = GLP_NF; 1.538 + else 1.539 + { npp_error(); 1.540 + return -1; 1.541 + } 1.542 + } 1.543 + else 1.544 + { npp_error(); 1.545 + return -1; 1.546 + } 1.547 + } 1.548 + /* compute value of x[q] with formula (2) */ 1.549 + npp->c_value[info->q] -= npp->c_value[info->s]; 1.550 + return 0; 1.551 +} 1.552 + 1.553 +/*********************************************************************** 1.554 +* NAME 1.555 +* 1.556 +* npp_lbnd_col - process column with (non-zero) lower bound 1.557 +* 1.558 +* SYNOPSIS 1.559 +* 1.560 +* #include "glpnpp.h" 1.561 +* void npp_lbnd_col(NPP *npp, NPPCOL *q); 1.562 +* 1.563 +* DESCRIPTION 1.564 +* 1.565 +* The routine npp_lbnd_col processes column q, which has (non-zero) 1.566 +* lower bound: 1.567 +* 1.568 +* l[q] <= x[q] (<= u[q]), (1) 1.569 +* 1.570 +* where l[q] < u[q], and upper bound may not exist (u[q] = +oo). 1.571 +* 1.572 +* PROBLEM TRANSFORMATION 1.573 +* 1.574 +* Column q can be replaced as follows: 1.575 +* 1.576 +* x[q] = l[q] + s, (2) 1.577 +* 1.578 +* where 1.579 +* 1.580 +* 0 <= s (<= u[q] - l[q]) (3) 1.581 +* 1.582 +* is a non-negative variable. 1.583 +* 1.584 +* Substituting x[q] from (2) into the objective row, we have: 1.585 +* 1.586 +* z = sum c[j] x[j] + c0 = 1.587 +* j 1.588 +* 1.589 +* = sum c[j] x[j] + c[q] x[q] + c0 = 1.590 +* j!=q 1.591 +* 1.592 +* = sum c[j] x[j] + c[q] (l[q] + s) + c0 = 1.593 +* j!=q 1.594 +* 1.595 +* = sum c[j] x[j] + c[q] s + c~0, 1.596 +* 1.597 +* where 1.598 +* 1.599 +* c~0 = c0 + c[q] l[q] (4) 1.600 +* 1.601 +* is the constant term of the objective in the transformed problem. 1.602 +* Similarly, substituting x[q] into constraint row i, we have: 1.603 +* 1.604 +* L[i] <= sum a[i,j] x[j] <= U[i] ==> 1.605 +* j 1.606 +* 1.607 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> 1.608 +* j!=q 1.609 +* 1.610 +* L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i] ==> 1.611 +* j!=q 1.612 +* 1.613 +* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i], 1.614 +* j!=q 1.615 +* 1.616 +* where 1.617 +* 1.618 +* L~[i] = L[i] - a[i,q] l[q], U~[i] = U[i] - a[i,q] l[q] (5) 1.619 +* 1.620 +* are lower and upper bounds of row i in the transformed problem, 1.621 +* resp. 1.622 +* 1.623 +* Transformation (2) does not affect the dual system. 1.624 +* 1.625 +* RECOVERING BASIC SOLUTION 1.626 +* 1.627 +* Status of column q in solution to the original problem is the same 1.628 +* as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU). 1.629 +* Value of column q is computed with formula (2). 1.630 +* 1.631 +* RECOVERING INTERIOR-POINT SOLUTION 1.632 +* 1.633 +* Value of column q is computed with formula (2). 1.634 +* 1.635 +* RECOVERING MIP SOLUTION 1.636 +* 1.637 +* Value of column q is computed with formula (2). */ 1.638 + 1.639 +struct bnd_col 1.640 +{ /* bounded column */ 1.641 + int q; 1.642 + /* column reference number for variables x[q] and s */ 1.643 + double bnd; 1.644 + /* lower/upper bound l[q] or u[q] */ 1.645 +}; 1.646 + 1.647 +static int rcv_lbnd_col(NPP *npp, void *info); 1.648 + 1.649 +void npp_lbnd_col(NPP *npp, NPPCOL *q) 1.650 +{ /* process column with (non-zero) lower bound */ 1.651 + struct bnd_col *info; 1.652 + NPPROW *i; 1.653 + NPPAIJ *aij; 1.654 + /* the column must have non-zero lower bound */ 1.655 + xassert(q->lb != 0.0); 1.656 + xassert(q->lb != -DBL_MAX); 1.657 + xassert(q->lb < q->ub); 1.658 + /* create transformation stack entry */ 1.659 + info = npp_push_tse(npp, 1.660 + rcv_lbnd_col, sizeof(struct bnd_col)); 1.661 + info->q = q->j; 1.662 + info->bnd = q->lb; 1.663 + /* substitute x[q] into objective row */ 1.664 + npp->c0 += q->coef * q->lb; 1.665 + /* substitute x[q] into constraint rows */ 1.666 + for (aij = q->ptr; aij != NULL; aij = aij->c_next) 1.667 + { i = aij->row; 1.668 + if (i->lb == i->ub) 1.669 + i->ub = (i->lb -= aij->val * q->lb); 1.670 + else 1.671 + { if (i->lb != -DBL_MAX) 1.672 + i->lb -= aij->val * q->lb; 1.673 + if (i->ub != +DBL_MAX) 1.674 + i->ub -= aij->val * q->lb; 1.675 + } 1.676 + } 1.677 + /* column x[q] becomes column s */ 1.678 + if (q->ub != +DBL_MAX) 1.679 + q->ub -= q->lb; 1.680 + q->lb = 0.0; 1.681 + return; 1.682 +} 1.683 + 1.684 +static int rcv_lbnd_col(NPP *npp, void *_info) 1.685 +{ /* recover column with (non-zero) lower bound */ 1.686 + struct bnd_col *info = _info; 1.687 + if (npp->sol == GLP_SOL) 1.688 + { if (npp->c_stat[info->q] == GLP_BS || 1.689 + npp->c_stat[info->q] == GLP_NL || 1.690 + npp->c_stat[info->q] == GLP_NU) 1.691 + npp->c_stat[info->q] = npp->c_stat[info->q]; 1.692 + else 1.693 + { npp_error(); 1.694 + return 1; 1.695 + } 1.696 + } 1.697 + /* compute value of x[q] with formula (2) */ 1.698 + npp->c_value[info->q] = info->bnd + npp->c_value[info->q]; 1.699 + return 0; 1.700 +} 1.701 + 1.702 +/*********************************************************************** 1.703 +* NAME 1.704 +* 1.705 +* npp_ubnd_col - process column with upper bound 1.706 +* 1.707 +* SYNOPSIS 1.708 +* 1.709 +* #include "glpnpp.h" 1.710 +* void npp_ubnd_col(NPP *npp, NPPCOL *q); 1.711 +* 1.712 +* DESCRIPTION 1.713 +* 1.714 +* The routine npp_ubnd_col processes column q, which has upper bound: 1.715 +* 1.716 +* (l[q] <=) x[q] <= u[q], (1) 1.717 +* 1.718 +* where l[q] < u[q], and lower bound may not exist (l[q] = -oo). 1.719 +* 1.720 +* PROBLEM TRANSFORMATION 1.721 +* 1.722 +* Column q can be replaced as follows: 1.723 +* 1.724 +* x[q] = u[q] - s, (2) 1.725 +* 1.726 +* where 1.727 +* 1.728 +* 0 <= s (<= u[q] - l[q]) (3) 1.729 +* 1.730 +* is a non-negative variable. 1.731 +* 1.732 +* Substituting x[q] from (2) into the objective row, we have: 1.733 +* 1.734 +* z = sum c[j] x[j] + c0 = 1.735 +* j 1.736 +* 1.737 +* = sum c[j] x[j] + c[q] x[q] + c0 = 1.738 +* j!=q 1.739 +* 1.740 +* = sum c[j] x[j] + c[q] (u[q] - s) + c0 = 1.741 +* j!=q 1.742 +* 1.743 +* = sum c[j] x[j] - c[q] s + c~0, 1.744 +* 1.745 +* where 1.746 +* 1.747 +* c~0 = c0 + c[q] u[q] (4) 1.748 +* 1.749 +* is the constant term of the objective in the transformed problem. 1.750 +* Similarly, substituting x[q] into constraint row i, we have: 1.751 +* 1.752 +* L[i] <= sum a[i,j] x[j] <= U[i] ==> 1.753 +* j 1.754 +* 1.755 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> 1.756 +* j!=q 1.757 +* 1.758 +* L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i] ==> 1.759 +* j!=q 1.760 +* 1.761 +* L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i], 1.762 +* j!=q 1.763 +* 1.764 +* where 1.765 +* 1.766 +* L~[i] = L[i] - a[i,q] u[q], U~[i] = U[i] - a[i,q] u[q] (5) 1.767 +* 1.768 +* are lower and upper bounds of row i in the transformed problem, 1.769 +* resp. 1.770 +* 1.771 +* Note that in the transformed problem coefficients c[q] and a[i,q] 1.772 +* change their sign. Thus, the row of the dual system corresponding to 1.773 +* column q: 1.774 +* 1.775 +* sum a[i,q] pi[i] + lambda[q] = c[q] (6) 1.776 +* i 1.777 +* 1.778 +* in the transformed problem becomes the following: 1.779 +* 1.780 +* sum (-a[i,q]) pi[i] + lambda[s] = -c[q]. (7) 1.781 +* i 1.782 +* 1.783 +* Therefore: 1.784 +* 1.785 +* lambda[q] = - lambda[s], (8) 1.786 +* 1.787 +* where lambda[q] is multiplier for column q, lambda[s] is multiplier 1.788 +* for column s. 1.789 +* 1.790 +* RECOVERING BASIC SOLUTION 1.791 +* 1.792 +* With respect to (8) status of column q in solution to the original 1.793 +* problem is determined by status of column s in solution to the 1.794 +* transformed problem as follows: 1.795 +* 1.796 +* +-----------------------+--------------------+ 1.797 +* | Status of column s | Status of column q | 1.798 +* | (transformed problem) | (original problem) | 1.799 +* +-----------------------+--------------------+ 1.800 +* | GLP_BS | GLP_BS | 1.801 +* | GLP_NL | GLP_NU | 1.802 +* | GLP_NU | GLP_NL | 1.803 +* +-----------------------+--------------------+ 1.804 +* 1.805 +* Value of column q is computed with formula (2). 1.806 +* 1.807 +* RECOVERING INTERIOR-POINT SOLUTION 1.808 +* 1.809 +* Value of column q is computed with formula (2). 1.810 +* 1.811 +* RECOVERING MIP SOLUTION 1.812 +* 1.813 +* Value of column q is computed with formula (2). */ 1.814 + 1.815 +static int rcv_ubnd_col(NPP *npp, void *info); 1.816 + 1.817 +void npp_ubnd_col(NPP *npp, NPPCOL *q) 1.818 +{ /* process column with upper bound */ 1.819 + struct bnd_col *info; 1.820 + NPPROW *i; 1.821 + NPPAIJ *aij; 1.822 + /* the column must have upper bound */ 1.823 + xassert(q->ub != +DBL_MAX); 1.824 + xassert(q->lb < q->ub); 1.825 + /* create transformation stack entry */ 1.826 + info = npp_push_tse(npp, 1.827 + rcv_ubnd_col, sizeof(struct bnd_col)); 1.828 + info->q = q->j; 1.829 + info->bnd = q->ub; 1.830 + /* substitute x[q] into objective row */ 1.831 + npp->c0 += q->coef * q->ub; 1.832 + q->coef = -q->coef; 1.833 + /* substitute x[q] into constraint rows */ 1.834 + for (aij = q->ptr; aij != NULL; aij = aij->c_next) 1.835 + { i = aij->row; 1.836 + if (i->lb == i->ub) 1.837 + i->ub = (i->lb -= aij->val * q->ub); 1.838 + else 1.839 + { if (i->lb != -DBL_MAX) 1.840 + i->lb -= aij->val * q->ub; 1.841 + if (i->ub != +DBL_MAX) 1.842 + i->ub -= aij->val * q->ub; 1.843 + } 1.844 + aij->val = -aij->val; 1.845 + } 1.846 + /* column x[q] becomes column s */ 1.847 + if (q->lb != -DBL_MAX) 1.848 + q->ub -= q->lb; 1.849 + else 1.850 + q->ub = +DBL_MAX; 1.851 + q->lb = 0.0; 1.852 + return; 1.853 +} 1.854 + 1.855 +static int rcv_ubnd_col(NPP *npp, void *_info) 1.856 +{ /* recover column with upper bound */ 1.857 + struct bnd_col *info = _info; 1.858 + if (npp->sol == GLP_BS) 1.859 + { if (npp->c_stat[info->q] == GLP_BS) 1.860 + npp->c_stat[info->q] = GLP_BS; 1.861 + else if (npp->c_stat[info->q] == GLP_NL) 1.862 + npp->c_stat[info->q] = GLP_NU; 1.863 + else if (npp->c_stat[info->q] == GLP_NU) 1.864 + npp->c_stat[info->q] = GLP_NL; 1.865 + else 1.866 + { npp_error(); 1.867 + return 1; 1.868 + } 1.869 + } 1.870 + /* compute value of x[q] with formula (2) */ 1.871 + npp->c_value[info->q] = info->bnd - npp->c_value[info->q]; 1.872 + return 0; 1.873 +} 1.874 + 1.875 +/*********************************************************************** 1.876 +* NAME 1.877 +* 1.878 +* npp_dbnd_col - process non-negative column with upper bound 1.879 +* 1.880 +* SYNOPSIS 1.881 +* 1.882 +* #include "glpnpp.h" 1.883 +* void npp_dbnd_col(NPP *npp, NPPCOL *q); 1.884 +* 1.885 +* DESCRIPTION 1.886 +* 1.887 +* The routine npp_dbnd_col processes column q, which is non-negative 1.888 +* and has upper bound: 1.889 +* 1.890 +* 0 <= x[q] <= u[q], (1) 1.891 +* 1.892 +* where u[q] > 0. 1.893 +* 1.894 +* PROBLEM TRANSFORMATION 1.895 +* 1.896 +* Upper bound of column q can be replaced by the following equality 1.897 +* constraint: 1.898 +* 1.899 +* x[q] + s = u[q], (2) 1.900 +* 1.901 +* where s >= 0 is a non-negative complement variable. 1.902 +* 1.903 +* Since in the primal system along with new row (2) there appears a 1.904 +* new column s having the only non-zero coefficient in this row, in 1.905 +* the dual system there appears a new row: 1.906 +* 1.907 +* (+1)pi + lambda[s] = 0, (3) 1.908 +* 1.909 +* where (+1) is coefficient at column s in row (2), pi is multiplier 1.910 +* for row (2), lambda[s] is multiplier for column s, 0 is coefficient 1.911 +* at column s in the objective row. 1.912 +* 1.913 +* RECOVERING BASIC SOLUTION 1.914 +* 1.915 +* Status of column q in solution to the original problem is determined 1.916 +* by its status and status of column s in solution to the transformed 1.917 +* problem as follows: 1.918 +* 1.919 +* +-----------------------------------+------------------+ 1.920 +* | Transformed problem | Original problem | 1.921 +* +-----------------+-----------------+------------------+ 1.922 +* | Status of col q | Status of col s | Status of col q | 1.923 +* +-----------------+-----------------+------------------+ 1.924 +* | GLP_BS | GLP_BS | GLP_BS | 1.925 +* | GLP_BS | GLP_NL | GLP_NU | 1.926 +* | GLP_NL | GLP_BS | GLP_NL | 1.927 +* | GLP_NL | GLP_NL | GLP_NL (*) | 1.928 +* +-----------------+-----------------+------------------+ 1.929 +* 1.930 +* Value of column q in solution to the original problem is the same as 1.931 +* in solution to the transformed problem. 1.932 +* 1.933 +* 1. Formally, in solution to the transformed problem columns q and s 1.934 +* cannot be non-basic at the same time, since the constraint (2) 1.935 +* would be violated. However, if u[q] is close to zero, violation 1.936 +* may be less than a working precision even if both columns q and s 1.937 +* are non-basic. In this degenerate case row (2) can be only basic, 1.938 +* i.e. non-active constraint (otherwise corresponding row of the 1.939 +* basis matrix would be zero). This allows to pivot out auxiliary 1.940 +* variable and pivot in column s, in which case the row becomes 1.941 +* active while column s becomes basic. 1.942 +* 1.943 +* 2. If column q is integral, column s is also integral. 1.944 +* 1.945 +* RECOVERING INTERIOR-POINT SOLUTION 1.946 +* 1.947 +* Value of column q in solution to the original problem is the same as 1.948 +* in solution to the transformed problem. 1.949 +* 1.950 +* RECOVERING MIP SOLUTION 1.951 +* 1.952 +* Value of column q in solution to the original problem is the same as 1.953 +* in solution to the transformed problem. */ 1.954 + 1.955 +struct dbnd_col 1.956 +{ /* double-bounded column */ 1.957 + int q; 1.958 + /* column reference number for variable x[q] */ 1.959 + int s; 1.960 + /* column reference number for complement variable s */ 1.961 +}; 1.962 + 1.963 +static int rcv_dbnd_col(NPP *npp, void *info); 1.964 + 1.965 +void npp_dbnd_col(NPP *npp, NPPCOL *q) 1.966 +{ /* process non-negative column with upper bound */ 1.967 + struct dbnd_col *info; 1.968 + NPPROW *p; 1.969 + NPPCOL *s; 1.970 + /* the column must be non-negative with upper bound */ 1.971 + xassert(q->lb == 0.0); 1.972 + xassert(q->ub > 0.0); 1.973 + xassert(q->ub != +DBL_MAX); 1.974 + /* create variable s */ 1.975 + s = npp_add_col(npp); 1.976 + s->is_int = q->is_int; 1.977 + s->lb = 0.0, s->ub = +DBL_MAX; 1.978 + /* create equality constraint (2) */ 1.979 + p = npp_add_row(npp); 1.980 + p->lb = p->ub = q->ub; 1.981 + npp_add_aij(npp, p, q, +1.0); 1.982 + npp_add_aij(npp, p, s, +1.0); 1.983 + /* create transformation stack entry */ 1.984 + info = npp_push_tse(npp, 1.985 + rcv_dbnd_col, sizeof(struct dbnd_col)); 1.986 + info->q = q->j; 1.987 + info->s = s->j; 1.988 + /* remove upper bound of x[q] */ 1.989 + q->ub = +DBL_MAX; 1.990 + return; 1.991 +} 1.992 + 1.993 +static int rcv_dbnd_col(NPP *npp, void *_info) 1.994 +{ /* recover non-negative column with upper bound */ 1.995 + struct dbnd_col *info = _info; 1.996 + if (npp->sol == GLP_BS) 1.997 + { if (npp->c_stat[info->q] == GLP_BS) 1.998 + { if (npp->c_stat[info->s] == GLP_BS) 1.999 + npp->c_stat[info->q] = GLP_BS; 1.1000 + else if (npp->c_stat[info->s] == GLP_NL) 1.1001 + npp->c_stat[info->q] = GLP_NU; 1.1002 + else 1.1003 + { npp_error(); 1.1004 + return 1; 1.1005 + } 1.1006 + } 1.1007 + else if (npp->c_stat[info->q] == GLP_NL) 1.1008 + { if (npp->c_stat[info->s] == GLP_BS || 1.1009 + npp->c_stat[info->s] == GLP_NL) 1.1010 + npp->c_stat[info->q] = GLP_NL; 1.1011 + else 1.1012 + { npp_error(); 1.1013 + return 1; 1.1014 + } 1.1015 + } 1.1016 + else 1.1017 + { npp_error(); 1.1018 + return 1; 1.1019 + } 1.1020 + } 1.1021 + return 0; 1.1022 +} 1.1023 + 1.1024 +/*********************************************************************** 1.1025 +* NAME 1.1026 +* 1.1027 +* npp_fixed_col - process fixed column 1.1028 +* 1.1029 +* SYNOPSIS 1.1030 +* 1.1031 +* #include "glpnpp.h" 1.1032 +* void npp_fixed_col(NPP *npp, NPPCOL *q); 1.1033 +* 1.1034 +* DESCRIPTION 1.1035 +* 1.1036 +* The routine npp_fixed_col processes column q, which is fixed: 1.1037 +* 1.1038 +* x[q] = s[q], (1) 1.1039 +* 1.1040 +* where s[q] is a fixed column value. 1.1041 +* 1.1042 +* PROBLEM TRANSFORMATION 1.1043 +* 1.1044 +* The value of a fixed column can be substituted into the objective 1.1045 +* and constraint rows that allows removing the column from the problem. 1.1046 +* 1.1047 +* Substituting x[q] = s[q] into the objective row, we have: 1.1048 +* 1.1049 +* z = sum c[j] x[j] + c0 = 1.1050 +* j 1.1051 +* 1.1052 +* = sum c[j] x[j] + c[q] x[q] + c0 = 1.1053 +* j!=q 1.1054 +* 1.1055 +* = sum c[j] x[j] + c[q] s[q] + c0 = 1.1056 +* j!=q 1.1057 +* 1.1058 +* = sum c[j] x[j] + c~0, 1.1059 +* j!=q 1.1060 +* 1.1061 +* where 1.1062 +* 1.1063 +* c~0 = c0 + c[q] s[q] (2) 1.1064 +* 1.1065 +* is the constant term of the objective in the transformed problem. 1.1066 +* Similarly, substituting x[q] = s[q] into constraint row i, we have: 1.1067 +* 1.1068 +* L[i] <= sum a[i,j] x[j] <= U[i] ==> 1.1069 +* j 1.1070 +* 1.1071 +* L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i] ==> 1.1072 +* j!=q 1.1073 +* 1.1074 +* L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i] ==> 1.1075 +* j!=q 1.1076 +* 1.1077 +* L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i], 1.1078 +* j!=q 1.1079 +* 1.1080 +* where 1.1081 +* 1.1082 +* L~[i] = L[i] - a[i,q] s[q], U~[i] = U[i] - a[i,q] s[q] (3) 1.1083 +* 1.1084 +* are lower and upper bounds of row i in the transformed problem, 1.1085 +* resp. 1.1086 +* 1.1087 +* RECOVERING BASIC SOLUTION 1.1088 +* 1.1089 +* Column q is assigned status GLP_NS and its value is assigned s[q]. 1.1090 +* 1.1091 +* RECOVERING INTERIOR-POINT SOLUTION 1.1092 +* 1.1093 +* Value of column q is assigned s[q]. 1.1094 +* 1.1095 +* RECOVERING MIP SOLUTION 1.1096 +* 1.1097 +* Value of column q is assigned s[q]. */ 1.1098 + 1.1099 +struct fixed_col 1.1100 +{ /* fixed column */ 1.1101 + int q; 1.1102 + /* column reference number for variable x[q] */ 1.1103 + double s; 1.1104 + /* value, at which x[q] is fixed */ 1.1105 +}; 1.1106 + 1.1107 +static int rcv_fixed_col(NPP *npp, void *info); 1.1108 + 1.1109 +void npp_fixed_col(NPP *npp, NPPCOL *q) 1.1110 +{ /* process fixed column */ 1.1111 + struct fixed_col *info; 1.1112 + NPPROW *i; 1.1113 + NPPAIJ *aij; 1.1114 + /* the column must be fixed */ 1.1115 + xassert(q->lb == q->ub); 1.1116 + /* create transformation stack entry */ 1.1117 + info = npp_push_tse(npp, 1.1118 + rcv_fixed_col, sizeof(struct fixed_col)); 1.1119 + info->q = q->j; 1.1120 + info->s = q->lb; 1.1121 + /* substitute x[q] = s[q] into objective row */ 1.1122 + npp->c0 += q->coef * q->lb; 1.1123 + /* substitute x[q] = s[q] into constraint rows */ 1.1124 + for (aij = q->ptr; aij != NULL; aij = aij->c_next) 1.1125 + { i = aij->row; 1.1126 + if (i->lb == i->ub) 1.1127 + i->ub = (i->lb -= aij->val * q->lb); 1.1128 + else 1.1129 + { if (i->lb != -DBL_MAX) 1.1130 + i->lb -= aij->val * q->lb; 1.1131 + if (i->ub != +DBL_MAX) 1.1132 + i->ub -= aij->val * q->lb; 1.1133 + } 1.1134 + } 1.1135 + /* remove the column from the problem */ 1.1136 + npp_del_col(npp, q); 1.1137 + return; 1.1138 +} 1.1139 + 1.1140 +static int rcv_fixed_col(NPP *npp, void *_info) 1.1141 +{ /* recover fixed column */ 1.1142 + struct fixed_col *info = _info; 1.1143 + if (npp->sol == GLP_SOL) 1.1144 + npp->c_stat[info->q] = GLP_NS; 1.1145 + npp->c_value[info->q] = info->s; 1.1146 + return 0; 1.1147 +} 1.1148 + 1.1149 +/*********************************************************************** 1.1150 +* NAME 1.1151 +* 1.1152 +* npp_make_equality - process row with almost identical bounds 1.1153 +* 1.1154 +* SYNOPSIS 1.1155 +* 1.1156 +* #include "glpnpp.h" 1.1157 +* int npp_make_equality(NPP *npp, NPPROW *p); 1.1158 +* 1.1159 +* DESCRIPTION 1.1160 +* 1.1161 +* The routine npp_make_equality processes row p: 1.1162 +* 1.1163 +* L[p] <= sum a[p,j] x[j] <= U[p], (1) 1.1164 +* j 1.1165 +* 1.1166 +* where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality 1.1167 +* constraint. 1.1168 +* 1.1169 +* RETURNS 1.1170 +* 1.1171 +* 0 - row bounds have not been changed; 1.1172 +* 1.1173 +* 1 - row has been replaced by equality constraint. 1.1174 +* 1.1175 +* PROBLEM TRANSFORMATION 1.1176 +* 1.1177 +* If bounds of row (1) are very close to each other: 1.1178 +* 1.1179 +* U[p] - L[p] <= eps, (2) 1.1180 +* 1.1181 +* where eps is an absolute tolerance for row value, the row can be 1.1182 +* replaced by the following almost equivalent equiality constraint: 1.1183 +* 1.1184 +* sum a[p,j] x[j] = b, (3) 1.1185 +* j 1.1186 +* 1.1187 +* where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens 1.1188 +* to be very close to its nearest integer: 1.1189 +* 1.1190 +* |b - floor(b + 0.5)| <= eps, (4) 1.1191 +* 1.1192 +* it is reasonable to use this nearest integer as the right-hand side. 1.1193 +* 1.1194 +* RECOVERING BASIC SOLUTION 1.1195 +* 1.1196 +* Status of row p in solution to the original problem is determined 1.1197 +* by its status and the sign of its multiplier pi[p] in solution to 1.1198 +* the transformed problem as follows: 1.1199 +* 1.1200 +* +-----------------------+---------+--------------------+ 1.1201 +* | Status of row p | Sign of | Status of row p | 1.1202 +* | (transformed problem) | pi[p] | (original problem) | 1.1203 +* +-----------------------+---------+--------------------+ 1.1204 +* | GLP_BS | + / - | GLP_BS | 1.1205 +* | GLP_NS | + | GLP_NL | 1.1206 +* | GLP_NS | - | GLP_NU | 1.1207 +* +-----------------------+---------+--------------------+ 1.1208 +* 1.1209 +* Value of row multiplier pi[p] in solution to the original problem is 1.1210 +* the same as in solution to the transformed problem. 1.1211 +* 1.1212 +* RECOVERING INTERIOR POINT SOLUTION 1.1213 +* 1.1214 +* Value of row multiplier pi[p] in solution to the original problem is 1.1215 +* the same as in solution to the transformed problem. 1.1216 +* 1.1217 +* RECOVERING MIP SOLUTION 1.1218 +* 1.1219 +* None needed. */ 1.1220 + 1.1221 +struct make_equality 1.1222 +{ /* row with almost identical bounds */ 1.1223 + int p; 1.1224 + /* row reference number */ 1.1225 +}; 1.1226 + 1.1227 +static int rcv_make_equality(NPP *npp, void *info); 1.1228 + 1.1229 +int npp_make_equality(NPP *npp, NPPROW *p) 1.1230 +{ /* process row with almost identical bounds */ 1.1231 + struct make_equality *info; 1.1232 + double b, eps, nint; 1.1233 + /* the row must be double-sided inequality */ 1.1234 + xassert(p->lb != -DBL_MAX); 1.1235 + xassert(p->ub != +DBL_MAX); 1.1236 + xassert(p->lb < p->ub); 1.1237 + /* check row bounds */ 1.1238 + eps = 1e-9 + 1e-12 * fabs(p->lb); 1.1239 + if (p->ub - p->lb > eps) return 0; 1.1240 + /* row bounds are very close to each other */ 1.1241 + /* create transformation stack entry */ 1.1242 + info = npp_push_tse(npp, 1.1243 + rcv_make_equality, sizeof(struct make_equality)); 1.1244 + info->p = p->i; 1.1245 + /* compute right-hand side */ 1.1246 + b = 0.5 * (p->ub + p->lb); 1.1247 + nint = floor(b + 0.5); 1.1248 + if (fabs(b - nint) <= eps) b = nint; 1.1249 + /* replace row p by almost equivalent equality constraint */ 1.1250 + p->lb = p->ub = b; 1.1251 + return 1; 1.1252 +} 1.1253 + 1.1254 +int rcv_make_equality(NPP *npp, void *_info) 1.1255 +{ /* recover row with almost identical bounds */ 1.1256 + struct make_equality *info = _info; 1.1257 + if (npp->sol == GLP_SOL) 1.1258 + { if (npp->r_stat[info->p] == GLP_BS) 1.1259 + npp->r_stat[info->p] = GLP_BS; 1.1260 + else if (npp->r_stat[info->p] == GLP_NS) 1.1261 + { if (npp->r_pi[info->p] >= 0.0) 1.1262 + npp->r_stat[info->p] = GLP_NL; 1.1263 + else 1.1264 + npp->r_stat[info->p] = GLP_NU; 1.1265 + } 1.1266 + else 1.1267 + { npp_error(); 1.1268 + return 1; 1.1269 + } 1.1270 + } 1.1271 + return 0; 1.1272 +} 1.1273 + 1.1274 +/*********************************************************************** 1.1275 +* NAME 1.1276 +* 1.1277 +* npp_make_fixed - process column with almost identical bounds 1.1278 +* 1.1279 +* SYNOPSIS 1.1280 +* 1.1281 +* #include "glpnpp.h" 1.1282 +* int npp_make_fixed(NPP *npp, NPPCOL *q); 1.1283 +* 1.1284 +* DESCRIPTION 1.1285 +* 1.1286 +* The routine npp_make_fixed processes column q: 1.1287 +* 1.1288 +* l[q] <= x[q] <= u[q], (1) 1.1289 +* 1.1290 +* where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper 1.1291 +* bounds. 1.1292 +* 1.1293 +* RETURNS 1.1294 +* 1.1295 +* 0 - column bounds have not been changed; 1.1296 +* 1.1297 +* 1 - column has been fixed. 1.1298 +* 1.1299 +* PROBLEM TRANSFORMATION 1.1300 +* 1.1301 +* If bounds of column (1) are very close to each other: 1.1302 +* 1.1303 +* u[q] - l[q] <= eps, (2) 1.1304 +* 1.1305 +* where eps is an absolute tolerance for column value, the column can 1.1306 +* be fixed: 1.1307 +* 1.1308 +* x[q] = s[q], (3) 1.1309 +* 1.1310 +* where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q] 1.1311 +* happens to be very close to its nearest integer: 1.1312 +* 1.1313 +* |s[q] - floor(s[q] + 0.5)| <= eps, (4) 1.1314 +* 1.1315 +* it is reasonable to use this nearest integer as the fixed value. 1.1316 +* 1.1317 +* RECOVERING BASIC SOLUTION 1.1318 +* 1.1319 +* In the dual system of the original (as well as transformed) problem 1.1320 +* column q corresponds to the following row: 1.1321 +* 1.1322 +* sum a[i,q] pi[i] + lambda[q] = c[q]. (5) 1.1323 +* i 1.1324 +* 1.1325 +* Since multipliers pi[i] are known for all rows from solution to the 1.1326 +* transformed problem, formula (5) allows computing value of multiplier 1.1327 +* (reduced cost) for column q: 1.1328 +* 1.1329 +* lambda[q] = c[q] - sum a[i,q] pi[i]. (6) 1.1330 +* i 1.1331 +* 1.1332 +* Status of column q in solution to the original problem is determined 1.1333 +* by its status and the sign of its multiplier lambda[q] in solution to 1.1334 +* the transformed problem as follows: 1.1335 +* 1.1336 +* +-----------------------+-----------+--------------------+ 1.1337 +* | Status of column q | Sign of | Status of column q | 1.1338 +* | (transformed problem) | lambda[q] | (original problem) | 1.1339 +* +-----------------------+-----------+--------------------+ 1.1340 +* | GLP_BS | + / - | GLP_BS | 1.1341 +* | GLP_NS | + | GLP_NL | 1.1342 +* | GLP_NS | - | GLP_NU | 1.1343 +* +-----------------------+-----------+--------------------+ 1.1344 +* 1.1345 +* Value of column q in solution to the original problem is the same as 1.1346 +* in solution to the transformed problem. 1.1347 +* 1.1348 +* RECOVERING INTERIOR POINT SOLUTION 1.1349 +* 1.1350 +* Value of column q in solution to the original problem is the same as 1.1351 +* in solution to the transformed problem. 1.1352 +* 1.1353 +* RECOVERING MIP SOLUTION 1.1354 +* 1.1355 +* None needed. */ 1.1356 + 1.1357 +struct make_fixed 1.1358 +{ /* column with almost identical bounds */ 1.1359 + int q; 1.1360 + /* column reference number */ 1.1361 + double c; 1.1362 + /* objective coefficient at x[q] */ 1.1363 + NPPLFE *ptr; 1.1364 + /* list of non-zero coefficients a[i,q] */ 1.1365 +}; 1.1366 + 1.1367 +static int rcv_make_fixed(NPP *npp, void *info); 1.1368 + 1.1369 +int npp_make_fixed(NPP *npp, NPPCOL *q) 1.1370 +{ /* process column with almost identical bounds */ 1.1371 + struct make_fixed *info; 1.1372 + NPPAIJ *aij; 1.1373 + NPPLFE *lfe; 1.1374 + double s, eps, nint; 1.1375 + /* the column must be double-bounded */ 1.1376 + xassert(q->lb != -DBL_MAX); 1.1377 + xassert(q->ub != +DBL_MAX); 1.1378 + xassert(q->lb < q->ub); 1.1379 + /* check column bounds */ 1.1380 + eps = 1e-9 + 1e-12 * fabs(q->lb); 1.1381 + if (q->ub - q->lb > eps) return 0; 1.1382 + /* column bounds are very close to each other */ 1.1383 + /* create transformation stack entry */ 1.1384 + info = npp_push_tse(npp, 1.1385 + rcv_make_fixed, sizeof(struct make_fixed)); 1.1386 + info->q = q->j; 1.1387 + info->c = q->coef; 1.1388 + info->ptr = NULL; 1.1389 + /* save column coefficients a[i,q] (needed for basic solution 1.1390 + only) */ 1.1391 + if (npp->sol == GLP_SOL) 1.1392 + { for (aij = q->ptr; aij != NULL; aij = aij->c_next) 1.1393 + { lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE)); 1.1394 + lfe->ref = aij->row->i; 1.1395 + lfe->val = aij->val; 1.1396 + lfe->next = info->ptr; 1.1397 + info->ptr = lfe; 1.1398 + } 1.1399 + } 1.1400 + /* compute column fixed value */ 1.1401 + s = 0.5 * (q->ub + q->lb); 1.1402 + nint = floor(s + 0.5); 1.1403 + if (fabs(s - nint) <= eps) s = nint; 1.1404 + /* make column q fixed */ 1.1405 + q->lb = q->ub = s; 1.1406 + return 1; 1.1407 +} 1.1408 + 1.1409 +static int rcv_make_fixed(NPP *npp, void *_info) 1.1410 +{ /* recover column with almost identical bounds */ 1.1411 + struct make_fixed *info = _info; 1.1412 + NPPLFE *lfe; 1.1413 + double lambda; 1.1414 + if (npp->sol == GLP_SOL) 1.1415 + { if (npp->c_stat[info->q] == GLP_BS) 1.1416 + npp->c_stat[info->q] = GLP_BS; 1.1417 + else if (npp->c_stat[info->q] == GLP_NS) 1.1418 + { /* compute multiplier for column q with formula (6) */ 1.1419 + lambda = info->c; 1.1420 + for (lfe = info->ptr; lfe != NULL; lfe = lfe->next) 1.1421 + lambda -= lfe->val * npp->r_pi[lfe->ref]; 1.1422 + /* assign status to non-basic column */ 1.1423 + if (lambda >= 0.0) 1.1424 + npp->c_stat[info->q] = GLP_NL; 1.1425 + else 1.1426 + npp->c_stat[info->q] = GLP_NU; 1.1427 + } 1.1428 + else 1.1429 + { npp_error(); 1.1430 + return 1; 1.1431 + } 1.1432 + } 1.1433 + return 0; 1.1434 +} 1.1435 + 1.1436 +/* eof */