src/glpnpp02.c
changeset 2 4c8956a7bdf4
equal deleted inserted replaced
-1:000000000000 0:56ab8ec8ba8d
       
     1 /* glpnpp02.c */
       
     2 
       
     3 /***********************************************************************
       
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
       
     5 *
       
     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>.
       
    10 *
       
    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.
       
    15 *
       
    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.
       
    20 *
       
    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 ***********************************************************************/
       
    24 
       
    25 #include "glpnpp.h"
       
    26 
       
    27 /***********************************************************************
       
    28 *  NAME
       
    29 *
       
    30 *  npp_free_row - process free (unbounded) row
       
    31 *
       
    32 *  SYNOPSIS
       
    33 *
       
    34 *  #include "glpnpp.h"
       
    35 *  void npp_free_row(NPP *npp, NPPROW *p);
       
    36 *
       
    37 *  DESCRIPTION
       
    38 *
       
    39 *  The routine npp_free_row processes row p, which is free (i.e. has
       
    40 *  no finite bounds):
       
    41 *
       
    42 *     -inf < sum a[p,j] x[j] < +inf.                                 (1)
       
    43 *             j
       
    44 *
       
    45 *  PROBLEM TRANSFORMATION
       
    46 *
       
    47 *  Constraint (1) cannot be active, so it is redundant and can be
       
    48 *  removed from the original problem.
       
    49 *
       
    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.
       
    53 *
       
    54 *  RECOVERING BASIC SOLUTION
       
    55 *
       
    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
       
    58 *  zero value.
       
    59 *
       
    60 *  RECOVERING INTERIOR-POINT SOLUTION
       
    61 *
       
    62 *  In solution to the original problem row p is inactive constraint,
       
    63 *  so its multiplier pi[p] is assigned zero value.
       
    64 *
       
    65 *  RECOVERING MIP SOLUTION
       
    66 *
       
    67 *  None needed. */
       
    68 
       
    69 struct free_row
       
    70 {     /* free (unbounded) row */
       
    71       int p;
       
    72       /* row reference number */
       
    73 };
       
    74 
       
    75 static int rcv_free_row(NPP *npp, void *info);
       
    76 
       
    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));
       
    85       info->p = p->i;
       
    86       /* remove the row from the problem */
       
    87       npp_del_row(npp, p);
       
    88       return;
       
    89 }
       
    90 
       
    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;
       
    98       return 0;
       
    99 }
       
   100 
       
   101 /***********************************************************************
       
   102 *  NAME
       
   103 *
       
   104 *  npp_geq_row - process row of 'not less than' type
       
   105 *
       
   106 *  SYNOPSIS
       
   107 *
       
   108 *  #include "glpnpp.h"
       
   109 *  void npp_geq_row(NPP *npp, NPPROW *p);
       
   110 *
       
   111 *  DESCRIPTION
       
   112 *
       
   113 *  The routine npp_geq_row processes row p, which is 'not less than'
       
   114 *  inequality constraint:
       
   115 *
       
   116 *     L[p] <= sum a[p,j] x[j] (<= U[p]),                             (1)
       
   117 *              j
       
   118 *
       
   119 *  where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
       
   120 *
       
   121 *  PROBLEM TRANSFORMATION
       
   122 *
       
   123 *  Constraint (1) can be replaced by equality constraint:
       
   124 *
       
   125 *     sum a[p,j] x[j] - s = L[p],                                    (2)
       
   126 *      j
       
   127 *
       
   128 *  where
       
   129 *
       
   130 *     0 <= s (<= U[p] - L[p])                                        (3)
       
   131 *
       
   132 *  is a non-negative surplus variable.
       
   133 *
       
   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
       
   136 *  new row:
       
   137 *
       
   138 *     (-1) pi[p] + lambda = 0,                                       (4)
       
   139 *
       
   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.
       
   143 *
       
   144 *  RECOVERING BASIC SOLUTION
       
   145 *
       
   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:
       
   149 *
       
   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 *     +-----------------+--------------------+------------------+
       
   162 *
       
   163 *  Value of row multiplier pi[p] in solution to the original problem
       
   164 *  is the same as in solution to the transformed problem.
       
   165 *
       
   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.
       
   170 *
       
   171 *  2. Though in the transformed problem row p is equality constraint,
       
   172 *     it may be basic due to primal degenerate solution.
       
   173 *
       
   174 *  RECOVERING INTERIOR-POINT SOLUTION
       
   175 *
       
   176 *  Value of row multiplier pi[p] in solution to the original problem
       
   177 *  is the same as in solution to the transformed problem.
       
   178 *
       
   179 *  RECOVERING MIP SOLUTION
       
   180 *
       
   181 *  None needed. */
       
   182 
       
   183 struct ineq_row
       
   184 {     /* inequality constraint row */
       
   185       int p;
       
   186       /* row reference number */
       
   187       int s;
       
   188       /* column reference number for slack/surplus variable */
       
   189 };
       
   190 
       
   191 static int rcv_geq_row(NPP *npp, void *info);
       
   192 
       
   193 void npp_geq_row(NPP *npp, NPPROW *p)
       
   194 {     /* process row of 'not less than' type */
       
   195       struct ineq_row *info;
       
   196       NPPCOL *s;
       
   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);
       
   202       s->lb = 0.0;
       
   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));
       
   209       info->p = p->i;
       
   210       info->s = s->j;
       
   211       /* replace the row by equality constraint */
       
   212       p->ub = p->lb;
       
   213       return;
       
   214 }
       
   215 
       
   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)
       
   222             {  npp_error();
       
   223                return 1;
       
   224             }
       
   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;
       
   228             else
       
   229             {  npp_error();
       
   230                return 1;
       
   231             }
       
   232          }
       
   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;
       
   240             else
       
   241             {  npp_error();
       
   242                return 1;
       
   243             }
       
   244          }
       
   245          else
       
   246          {  npp_error();
       
   247             return 1;
       
   248          }
       
   249       }
       
   250       return 0;
       
   251 }
       
   252 
       
   253 /***********************************************************************
       
   254 *  NAME
       
   255 *
       
   256 *  npp_leq_row - process row of 'not greater than' type
       
   257 *
       
   258 *  SYNOPSIS
       
   259 *
       
   260 *  #include "glpnpp.h"
       
   261 *  void npp_leq_row(NPP *npp, NPPROW *p);
       
   262 *
       
   263 *  DESCRIPTION
       
   264 *
       
   265 *  The routine npp_leq_row processes row p, which is 'not greater than'
       
   266 *  inequality constraint:
       
   267 *
       
   268 *     (L[p] <=) sum a[p,j] x[j] <= U[p],                             (1)
       
   269 *                j
       
   270 *
       
   271 *  where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
       
   272 *
       
   273 *  PROBLEM TRANSFORMATION
       
   274 *
       
   275 *  Constraint (1) can be replaced by equality constraint:
       
   276 *
       
   277 *     sum a[p,j] x[j] + s = L[p],                                    (2)
       
   278 *      j
       
   279 *
       
   280 *  where
       
   281 *
       
   282 *     0 <= s (<= U[p] - L[p])                                        (3)
       
   283 *
       
   284 *  is a non-negative slack variable.
       
   285 *
       
   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
       
   288 *  new row:
       
   289 *
       
   290 *     (+1) pi[p] + lambda = 0,                                       (4)
       
   291 *
       
   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.
       
   295 *
       
   296 *  RECOVERING BASIC SOLUTION
       
   297 *
       
   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:
       
   301 *
       
   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 *     +-----------------+--------------------+------------------+
       
   314 *
       
   315 *  Value of row multiplier pi[p] in solution to the original problem
       
   316 *  is the same as in solution to the transformed problem.
       
   317 *
       
   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.
       
   322 *
       
   323 *  2. Though in the transformed problem row p is equality constraint,
       
   324 *     it may be basic due to primal degeneracy.
       
   325 *
       
   326 *  RECOVERING INTERIOR-POINT SOLUTION
       
   327 *
       
   328 *  Value of row multiplier pi[p] in solution to the original problem
       
   329 *  is the same as in solution to the transformed problem.
       
   330 *
       
   331 *  RECOVERING MIP SOLUTION
       
   332 *
       
   333 *  None needed. */
       
   334 
       
   335 static int rcv_leq_row(NPP *npp, void *info);
       
   336 
       
   337 void npp_leq_row(NPP *npp, NPPROW *p)
       
   338 {     /* process row of 'not greater than' type */
       
   339       struct ineq_row *info;
       
   340       NPPCOL *s;
       
   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);
       
   346       s->lb = 0.0;
       
   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));
       
   353       info->p = p->i;
       
   354       info->s = s->j;
       
   355       /* replace the row by equality constraint */
       
   356       p->lb = p->ub;
       
   357       return;
       
   358 }
       
   359 
       
   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)
       
   366             {  npp_error();
       
   367                return 1;
       
   368             }
       
   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;
       
   372             else
       
   373             {  npp_error();
       
   374                return 1;
       
   375             }
       
   376          }
       
   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;
       
   384             else
       
   385             {  npp_error();
       
   386                return 1;
       
   387             }
       
   388          }
       
   389          else
       
   390          {  npp_error();
       
   391             return 1;
       
   392          }
       
   393       }
       
   394       return 0;
       
   395 }
       
   396 
       
   397 /***********************************************************************
       
   398 *  NAME
       
   399 *
       
   400 *  npp_free_col - process free (unbounded) column
       
   401 *
       
   402 *  SYNOPSIS
       
   403 *
       
   404 *  #include "glpnpp.h"
       
   405 *  void npp_free_col(NPP *npp, NPPCOL *q);
       
   406 *
       
   407 *  DESCRIPTION
       
   408 *
       
   409 *  The routine npp_free_col processes column q, which is free (i.e. has
       
   410 *  no finite bounds):
       
   411 *
       
   412 *     -oo < x[q] < +oo.                                              (1)
       
   413 *
       
   414 *  PROBLEM TRANSFORMATION
       
   415 *
       
   416 *  Free (unbounded) variable can be replaced by the difference of two
       
   417 *  non-negative variables:
       
   418 *
       
   419 *     x[q] = s' - s'',   s', s'' >= 0.                               (2)
       
   420 *
       
   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':
       
   426 *
       
   427 *     sum a[i,q] pi[i] + lambda' = c[q],                             (3)
       
   428 *      i
       
   429 *
       
   430 *  the row which corresponds to column s'' is the following:
       
   431 *
       
   432 *     sum (-a[i,q]) pi[i] + lambda'' = -c[q].                        (4)
       
   433 *      i
       
   434 *
       
   435 *  Then from (3) and (4) it follows that:
       
   436 *
       
   437 *     lambda' + lambda'' = 0   =>   lambda' = lmabda'' = 0,          (5)
       
   438 *
       
   439 *  where lambda' and lambda'' are multipliers for columns s' and s'',
       
   440 *  resp.
       
   441 *
       
   442 *  RECOVERING BASIC SOLUTION
       
   443 *
       
   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:
       
   447 *
       
   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 *     +------------------+-------------------+------------------+
       
   458 *
       
   459 *  Value of column q is computed with formula (2).
       
   460 *
       
   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.
       
   464 *
       
   465 *  2. Though column q is free, it can be non-basic due to dual
       
   466 *     degeneracy.
       
   467 *
       
   468 *  3. If column q is integral, columns s' and s'' are also integral.
       
   469 *
       
   470 *  RECOVERING INTERIOR-POINT SOLUTION
       
   471 *
       
   472 *  Value of column q is computed with formula (2).
       
   473 *
       
   474 *  RECOVERING MIP SOLUTION
       
   475 *
       
   476 *  Value of column q is computed with formula (2). */
       
   477 
       
   478 struct free_col
       
   479 {     /* free (unbounded) column */
       
   480       int q;
       
   481       /* column reference number for variables x[q] and s' */
       
   482       int s;
       
   483       /* column reference number for variable s'' */
       
   484 };
       
   485 
       
   486 static int rcv_free_col(NPP *npp, void *info);
       
   487 
       
   488 void npp_free_col(NPP *npp, NPPCOL *q)
       
   489 {     /* process free (unbounded) column */
       
   490       struct free_col *info;
       
   491       NPPCOL *s;
       
   492       NPPAIJ *aij;
       
   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 */
       
   502       s->coef = -q->coef;
       
   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));
       
   509       info->q = q->j;
       
   510       info->s = s->j;
       
   511       return;
       
   512 }
       
   513 
       
   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)
       
   520             {  npp_error();
       
   521                return 1;
       
   522             }
       
   523             else if (npp->c_stat[info->s] == GLP_NL)
       
   524                npp->c_stat[info->q] = GLP_BS;
       
   525             else
       
   526             {  npp_error();
       
   527                return -1;
       
   528             }
       
   529          }
       
   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;
       
   535             else
       
   536             {  npp_error();
       
   537                return -1;
       
   538             }
       
   539          }
       
   540          else
       
   541          {  npp_error();
       
   542             return -1;
       
   543          }
       
   544       }
       
   545       /* compute value of x[q] with formula (2) */
       
   546       npp->c_value[info->q] -= npp->c_value[info->s];
       
   547       return 0;
       
   548 }
       
   549 
       
   550 /***********************************************************************
       
   551 *  NAME
       
   552 *
       
   553 *  npp_lbnd_col - process column with (non-zero) lower bound
       
   554 *
       
   555 *  SYNOPSIS
       
   556 *
       
   557 *  #include "glpnpp.h"
       
   558 *  void npp_lbnd_col(NPP *npp, NPPCOL *q);
       
   559 *
       
   560 *  DESCRIPTION
       
   561 *
       
   562 *  The routine npp_lbnd_col processes column q, which has (non-zero)
       
   563 *  lower bound:
       
   564 *
       
   565 *     l[q] <= x[q] (<= u[q]),                                        (1)
       
   566 *
       
   567 *  where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
       
   568 *
       
   569 *  PROBLEM TRANSFORMATION
       
   570 *
       
   571 *  Column q can be replaced as follows:
       
   572 *
       
   573 *     x[q] = l[q] + s,                                               (2)
       
   574 *
       
   575 *  where
       
   576 *
       
   577 *     0 <= s (<= u[q] - l[q])                                        (3)
       
   578 *
       
   579 *  is a non-negative variable.
       
   580 *
       
   581 *  Substituting x[q] from (2) into the objective row, we have:
       
   582 *
       
   583 *     z = sum c[j] x[j] + c0 =
       
   584 *          j
       
   585 *
       
   586 *       = sum c[j] x[j] + c[q] x[q] + c0 =
       
   587 *         j!=q
       
   588 *
       
   589 *       = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
       
   590 *         j!=q
       
   591 *
       
   592 *       = sum c[j] x[j] + c[q] s + c~0,
       
   593 *
       
   594 *  where
       
   595 *
       
   596 *     c~0 = c0 + c[q] l[q]                                           (4)
       
   597 *
       
   598 *  is the constant term of the objective in the transformed problem.
       
   599 *  Similarly, substituting x[q] into constraint row i, we have:
       
   600 *
       
   601 *     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
       
   602 *              j
       
   603 *
       
   604 *     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
       
   605 *             j!=q
       
   606 *
       
   607 *     L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i]  ==>
       
   608 *             j!=q
       
   609 *
       
   610 *     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
       
   611 *              j!=q
       
   612 *
       
   613 *  where
       
   614 *
       
   615 *     L~[i] = L[i] - a[i,q] l[q],  U~[i] = U[i] - a[i,q] l[q]        (5)
       
   616 *
       
   617 *  are lower and upper bounds of row i in the transformed problem,
       
   618 *  resp.
       
   619 *
       
   620 *  Transformation (2) does not affect the dual system.
       
   621 *
       
   622 *  RECOVERING BASIC SOLUTION
       
   623 *
       
   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).
       
   627 *
       
   628 *  RECOVERING INTERIOR-POINT SOLUTION
       
   629 *
       
   630 *  Value of column q is computed with formula (2).
       
   631 *
       
   632 *  RECOVERING MIP SOLUTION
       
   633 *
       
   634 *  Value of column q is computed with formula (2). */
       
   635 
       
   636 struct bnd_col
       
   637 {     /* bounded column */
       
   638       int q;
       
   639       /* column reference number for variables x[q] and s */
       
   640       double bnd;
       
   641       /* lower/upper bound l[q] or u[q] */
       
   642 };
       
   643 
       
   644 static int rcv_lbnd_col(NPP *npp, void *info);
       
   645 
       
   646 void npp_lbnd_col(NPP *npp, NPPCOL *q)
       
   647 {     /* process column with (non-zero) lower bound */
       
   648       struct bnd_col *info;
       
   649       NPPROW *i;
       
   650       NPPAIJ *aij;
       
   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));
       
   658       info->q = q->j;
       
   659       info->bnd = q->lb;
       
   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)
       
   664       {  i = aij->row;
       
   665          if (i->lb == i->ub)
       
   666             i->ub = (i->lb -= aij->val * q->lb);
       
   667          else
       
   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;
       
   672          }
       
   673       }
       
   674       /* column x[q] becomes column s */
       
   675       if (q->ub != +DBL_MAX)
       
   676          q->ub -= q->lb;
       
   677       q->lb = 0.0;
       
   678       return;
       
   679 }
       
   680 
       
   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];
       
   689          else
       
   690          {  npp_error();
       
   691             return 1;
       
   692          }
       
   693       }
       
   694       /* compute value of x[q] with formula (2) */
       
   695       npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
       
   696       return 0;
       
   697 }
       
   698 
       
   699 /***********************************************************************
       
   700 *  NAME
       
   701 *
       
   702 *  npp_ubnd_col - process column with upper bound
       
   703 *
       
   704 *  SYNOPSIS
       
   705 *
       
   706 *  #include "glpnpp.h"
       
   707 *  void npp_ubnd_col(NPP *npp, NPPCOL *q);
       
   708 *
       
   709 *  DESCRIPTION
       
   710 *
       
   711 *  The routine npp_ubnd_col processes column q, which has upper bound:
       
   712 *
       
   713 *     (l[q] <=) x[q] <= u[q],                                        (1)
       
   714 *
       
   715 *  where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
       
   716 *
       
   717 *  PROBLEM TRANSFORMATION
       
   718 *
       
   719 *  Column q can be replaced as follows:
       
   720 *
       
   721 *     x[q] = u[q] - s,                                               (2)
       
   722 *
       
   723 *  where
       
   724 *
       
   725 *     0 <= s (<= u[q] - l[q])                                        (3)
       
   726 *
       
   727 *  is a non-negative variable.
       
   728 *
       
   729 *  Substituting x[q] from (2) into the objective row, we have:
       
   730 *
       
   731 *     z = sum c[j] x[j] + c0 =
       
   732 *          j
       
   733 *
       
   734 *       = sum c[j] x[j] + c[q] x[q] + c0 =
       
   735 *         j!=q
       
   736 *
       
   737 *       = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
       
   738 *         j!=q
       
   739 *
       
   740 *       = sum c[j] x[j] - c[q] s + c~0,
       
   741 *
       
   742 *  where
       
   743 *
       
   744 *     c~0 = c0 + c[q] u[q]                                           (4)
       
   745 *
       
   746 *  is the constant term of the objective in the transformed problem.
       
   747 *  Similarly, substituting x[q] into constraint row i, we have:
       
   748 *
       
   749 *     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
       
   750 *              j
       
   751 *
       
   752 *     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
       
   753 *             j!=q
       
   754 *
       
   755 *     L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i]  ==>
       
   756 *             j!=q
       
   757 *
       
   758 *     L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
       
   759 *              j!=q
       
   760 *
       
   761 *  where
       
   762 *
       
   763 *     L~[i] = L[i] - a[i,q] u[q],  U~[i] = U[i] - a[i,q] u[q]        (5)
       
   764 *
       
   765 *  are lower and upper bounds of row i in the transformed problem,
       
   766 *  resp.
       
   767 *
       
   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
       
   770 *  column q:
       
   771 *
       
   772 *     sum a[i,q] pi[i] + lambda[q] = c[q]                            (6)
       
   773 *      i
       
   774 *
       
   775 *  in the transformed problem becomes the following:
       
   776 *
       
   777 *     sum (-a[i,q]) pi[i] + lambda[s] = -c[q].                       (7)
       
   778 *      i
       
   779 *
       
   780 *  Therefore:
       
   781 *
       
   782 *     lambda[q] = - lambda[s],                                       (8)
       
   783 *
       
   784 *  where lambda[q] is multiplier for column q, lambda[s] is multiplier
       
   785 *  for column s.
       
   786 *
       
   787 *  RECOVERING BASIC SOLUTION
       
   788 *
       
   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:
       
   792 *
       
   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 *     +-----------------------+--------------------+
       
   801 *
       
   802 *  Value of column q is computed with formula (2).
       
   803 *
       
   804 *  RECOVERING INTERIOR-POINT SOLUTION
       
   805 *
       
   806 *  Value of column q is computed with formula (2).
       
   807 *
       
   808 *  RECOVERING MIP SOLUTION
       
   809 *
       
   810 *  Value of column q is computed with formula (2). */
       
   811 
       
   812 static int rcv_ubnd_col(NPP *npp, void *info);
       
   813 
       
   814 void npp_ubnd_col(NPP *npp, NPPCOL *q)
       
   815 {     /* process column with upper bound */
       
   816       struct bnd_col *info;
       
   817       NPPROW *i;
       
   818       NPPAIJ *aij;
       
   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));
       
   825       info->q = q->j;
       
   826       info->bnd = q->ub;
       
   827       /* substitute x[q] into objective row */
       
   828       npp->c0 += q->coef * q->ub;
       
   829       q->coef = -q->coef;
       
   830       /* substitute x[q] into constraint rows */
       
   831       for (aij = q->ptr; aij != NULL; aij = aij->c_next)
       
   832       {  i = aij->row;
       
   833          if (i->lb == i->ub)
       
   834             i->ub = (i->lb -= aij->val * q->ub);
       
   835          else
       
   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;
       
   840          }
       
   841          aij->val = -aij->val;
       
   842       }
       
   843       /* column x[q] becomes column s */
       
   844       if (q->lb != -DBL_MAX)
       
   845          q->ub -= q->lb;
       
   846       else
       
   847          q->ub = +DBL_MAX;
       
   848       q->lb = 0.0;
       
   849       return;
       
   850 }
       
   851 
       
   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;
       
   862          else
       
   863          {  npp_error();
       
   864             return 1;
       
   865          }
       
   866       }
       
   867       /* compute value of x[q] with formula (2) */
       
   868       npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
       
   869       return 0;
       
   870 }
       
   871 
       
   872 /***********************************************************************
       
   873 *  NAME
       
   874 *
       
   875 *  npp_dbnd_col - process non-negative column with upper bound
       
   876 *
       
   877 *  SYNOPSIS
       
   878 *
       
   879 *  #include "glpnpp.h"
       
   880 *  void npp_dbnd_col(NPP *npp, NPPCOL *q);
       
   881 *
       
   882 *  DESCRIPTION
       
   883 *
       
   884 *  The routine npp_dbnd_col processes column q, which is non-negative
       
   885 *  and has upper bound:
       
   886 *
       
   887 *     0 <= x[q] <= u[q],                                             (1)
       
   888 *
       
   889 *  where u[q] > 0.
       
   890 *
       
   891 *  PROBLEM TRANSFORMATION
       
   892 *
       
   893 *  Upper bound of column q can be replaced by the following equality
       
   894 *  constraint:
       
   895 *
       
   896 *     x[q] + s = u[q],                                               (2)
       
   897 *
       
   898 *  where s >= 0 is a non-negative complement variable.
       
   899 *
       
   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:
       
   903 *
       
   904 *     (+1)pi + lambda[s] = 0,                                        (3)
       
   905 *
       
   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.
       
   909 *
       
   910 *  RECOVERING BASIC SOLUTION
       
   911 *
       
   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:
       
   915 *
       
   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 *     +-----------------+-----------------+------------------+
       
   926 *
       
   927 *  Value of column q in solution to the original problem is the same as
       
   928 *  in solution to the transformed problem.
       
   929 *
       
   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.
       
   939 *
       
   940 *  2. If column q is integral, column s is also integral.
       
   941 *
       
   942 *  RECOVERING INTERIOR-POINT SOLUTION
       
   943 *
       
   944 *  Value of column q in solution to the original problem is the same as
       
   945 *  in solution to the transformed problem.
       
   946 *
       
   947 *  RECOVERING MIP SOLUTION
       
   948 *
       
   949 *  Value of column q in solution to the original problem is the same as
       
   950 *  in solution to the transformed problem. */
       
   951 
       
   952 struct dbnd_col
       
   953 {     /* double-bounded column */
       
   954       int q;
       
   955       /* column reference number for variable x[q] */
       
   956       int s;
       
   957       /* column reference number for complement variable s */
       
   958 };
       
   959 
       
   960 static int rcv_dbnd_col(NPP *npp, void *info);
       
   961 
       
   962 void npp_dbnd_col(NPP *npp, NPPCOL *q)
       
   963 {     /* process non-negative column with upper bound */
       
   964       struct dbnd_col *info;
       
   965       NPPROW *p;
       
   966       NPPCOL *s;
       
   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));
       
   983       info->q = q->j;
       
   984       info->s = s->j;
       
   985       /* remove upper bound of x[q] */
       
   986       q->ub = +DBL_MAX;
       
   987       return;
       
   988 }
       
   989 
       
   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;
       
   999             else
       
  1000             {  npp_error();
       
  1001                return 1;
       
  1002             }
       
  1003          }
       
  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;
       
  1008             else
       
  1009             {  npp_error();
       
  1010                return 1;
       
  1011             }
       
  1012          }
       
  1013          else
       
  1014          {  npp_error();
       
  1015             return 1;
       
  1016          }
       
  1017       }
       
  1018       return 0;
       
  1019 }
       
  1020 
       
  1021 /***********************************************************************
       
  1022 *  NAME
       
  1023 *
       
  1024 *  npp_fixed_col - process fixed column
       
  1025 *
       
  1026 *  SYNOPSIS
       
  1027 *
       
  1028 *  #include "glpnpp.h"
       
  1029 *  void npp_fixed_col(NPP *npp, NPPCOL *q);
       
  1030 *
       
  1031 *  DESCRIPTION
       
  1032 *
       
  1033 *  The routine npp_fixed_col processes column q, which is fixed:
       
  1034 *
       
  1035 *     x[q] = s[q],                                                   (1)
       
  1036 *
       
  1037 *  where s[q] is a fixed column value.
       
  1038 *
       
  1039 *  PROBLEM TRANSFORMATION
       
  1040 *
       
  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.
       
  1043 *
       
  1044 *  Substituting x[q] = s[q] into the objective row, we have:
       
  1045 *
       
  1046 *     z = sum c[j] x[j] + c0 =
       
  1047 *          j
       
  1048 *
       
  1049 *       = sum c[j] x[j] + c[q] x[q] + c0 =
       
  1050 *         j!=q
       
  1051 *
       
  1052 *       = sum c[j] x[j] + c[q] s[q] + c0 =
       
  1053 *         j!=q
       
  1054 *
       
  1055 *       = sum c[j] x[j] + c~0,
       
  1056 *         j!=q
       
  1057 *
       
  1058 *  where
       
  1059 *
       
  1060 *     c~0 = c0 + c[q] s[q]                                           (2)
       
  1061 *
       
  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:
       
  1064 *
       
  1065 *     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
       
  1066 *              j
       
  1067 *
       
  1068 *     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
       
  1069 *             j!=q
       
  1070 *
       
  1071 *     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]  ==>
       
  1072 *             j!=q
       
  1073 *
       
  1074 *     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
       
  1075 *              j!=q
       
  1076 *
       
  1077 *  where
       
  1078 *
       
  1079 *     L~[i] = L[i] - a[i,q] s[q],  U~[i] = U[i] - a[i,q] s[q]        (3)
       
  1080 *
       
  1081 *  are lower and upper bounds of row i in the transformed problem,
       
  1082 *  resp.
       
  1083 *
       
  1084 *  RECOVERING BASIC SOLUTION
       
  1085 *
       
  1086 *  Column q is assigned status GLP_NS and its value is assigned s[q].
       
  1087 *
       
  1088 *  RECOVERING INTERIOR-POINT SOLUTION
       
  1089 *
       
  1090 *  Value of column q is assigned s[q].
       
  1091 *
       
  1092 *  RECOVERING MIP SOLUTION
       
  1093 *
       
  1094 *  Value of column q is assigned s[q]. */
       
  1095 
       
  1096 struct fixed_col
       
  1097 {     /* fixed column */
       
  1098       int q;
       
  1099       /* column reference number for variable x[q] */
       
  1100       double s;
       
  1101       /* value, at which x[q] is fixed */
       
  1102 };
       
  1103 
       
  1104 static int rcv_fixed_col(NPP *npp, void *info);
       
  1105 
       
  1106 void npp_fixed_col(NPP *npp, NPPCOL *q)
       
  1107 {     /* process fixed column */
       
  1108       struct fixed_col *info;
       
  1109       NPPROW *i;
       
  1110       NPPAIJ *aij;
       
  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));
       
  1116       info->q = q->j;
       
  1117       info->s = q->lb;
       
  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)
       
  1122       {  i = aij->row;
       
  1123          if (i->lb == i->ub)
       
  1124             i->ub = (i->lb -= aij->val * q->lb);
       
  1125          else
       
  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;
       
  1130          }
       
  1131       }
       
  1132       /* remove the column from the problem */
       
  1133       npp_del_col(npp, q);
       
  1134       return;
       
  1135 }
       
  1136 
       
  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;
       
  1143       return 0;
       
  1144 }
       
  1145 
       
  1146 /***********************************************************************
       
  1147 *  NAME
       
  1148 *
       
  1149 *  npp_make_equality - process row with almost identical bounds
       
  1150 *
       
  1151 *  SYNOPSIS
       
  1152 *
       
  1153 *  #include "glpnpp.h"
       
  1154 *  int npp_make_equality(NPP *npp, NPPROW *p);
       
  1155 *
       
  1156 *  DESCRIPTION
       
  1157 *
       
  1158 *  The routine npp_make_equality processes row p:
       
  1159 *
       
  1160 *     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
       
  1161 *              j
       
  1162 *
       
  1163 *  where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
       
  1164 *  constraint.
       
  1165 *
       
  1166 *  RETURNS
       
  1167 *
       
  1168 *  0 - row bounds have not been changed;
       
  1169 *
       
  1170 *  1 - row has been replaced by equality constraint.
       
  1171 *
       
  1172 *  PROBLEM TRANSFORMATION
       
  1173 *
       
  1174 *  If bounds of row (1) are very close to each other:
       
  1175 *
       
  1176 *     U[p] - L[p] <= eps,                                            (2)
       
  1177 *
       
  1178 *  where eps is an absolute tolerance for row value, the row can be
       
  1179 *  replaced by the following almost equivalent equiality constraint:
       
  1180 *
       
  1181 *     sum a[p,j] x[j] = b,                                           (3)
       
  1182 *      j
       
  1183 *
       
  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:
       
  1186 *
       
  1187 *     |b - floor(b + 0.5)| <= eps,                                   (4)
       
  1188 *
       
  1189 *  it is reasonable to use this nearest integer as the right-hand side.
       
  1190 *
       
  1191 *  RECOVERING BASIC SOLUTION
       
  1192 *
       
  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:
       
  1196 *
       
  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 *     +-----------------------+---------+--------------------+
       
  1205 *
       
  1206 *  Value of row multiplier pi[p] in solution to the original problem is
       
  1207 *  the same as in solution to the transformed problem.
       
  1208 *
       
  1209 *  RECOVERING INTERIOR POINT SOLUTION
       
  1210 *
       
  1211 *  Value of row multiplier pi[p] in solution to the original problem is
       
  1212 *  the same as in solution to the transformed problem.
       
  1213 *
       
  1214 *  RECOVERING MIP SOLUTION
       
  1215 *
       
  1216 *  None needed. */
       
  1217 
       
  1218 struct make_equality
       
  1219 {     /* row with almost identical bounds */
       
  1220       int p;
       
  1221       /* row reference number */
       
  1222 };
       
  1223 
       
  1224 static int rcv_make_equality(NPP *npp, void *info);
       
  1225 
       
  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));
       
  1241       info->p = p->i;
       
  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 */
       
  1247       p->lb = p->ub = b;
       
  1248       return 1;
       
  1249 }
       
  1250 
       
  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;
       
  1260             else
       
  1261                npp->r_stat[info->p] = GLP_NU;
       
  1262          }
       
  1263          else
       
  1264          {  npp_error();
       
  1265             return 1;
       
  1266          }
       
  1267       }
       
  1268       return 0;
       
  1269 }
       
  1270 
       
  1271 /***********************************************************************
       
  1272 *  NAME
       
  1273 *
       
  1274 *  npp_make_fixed - process column with almost identical bounds
       
  1275 *
       
  1276 *  SYNOPSIS
       
  1277 *
       
  1278 *  #include "glpnpp.h"
       
  1279 *  int npp_make_fixed(NPP *npp, NPPCOL *q);
       
  1280 *
       
  1281 *  DESCRIPTION
       
  1282 *
       
  1283 *  The routine npp_make_fixed processes column q:
       
  1284 *
       
  1285 *     l[q] <= x[q] <= u[q],                                          (1)
       
  1286 *
       
  1287 *  where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
       
  1288 *  bounds.
       
  1289 *
       
  1290 *  RETURNS
       
  1291 *
       
  1292 *  0 - column bounds have not been changed;
       
  1293 *
       
  1294 *  1 - column has been fixed.
       
  1295 *
       
  1296 *  PROBLEM TRANSFORMATION
       
  1297 *
       
  1298 *  If bounds of column (1) are very close to each other:
       
  1299 *
       
  1300 *     u[q] - l[q] <= eps,                                            (2)
       
  1301 *
       
  1302 *  where eps is an absolute tolerance for column value, the column can
       
  1303 *  be fixed:
       
  1304 *
       
  1305 *     x[q] = s[q],                                                   (3)
       
  1306 *
       
  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:
       
  1309 *
       
  1310 *     |s[q] - floor(s[q] + 0.5)| <= eps,                             (4)
       
  1311 *
       
  1312 *  it is reasonable to use this nearest integer as the fixed value.
       
  1313 *
       
  1314 *  RECOVERING BASIC SOLUTION
       
  1315 *
       
  1316 *  In the dual system of the original (as well as transformed) problem
       
  1317 *  column q corresponds to the following row:
       
  1318 *
       
  1319 *     sum a[i,q] pi[i] + lambda[q] = c[q].                           (5)
       
  1320 *      i
       
  1321 *
       
  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:
       
  1325 *
       
  1326 *     lambda[q] = c[q] - sum a[i,q] pi[i].                           (6)
       
  1327 *                         i
       
  1328 *
       
  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:
       
  1332 *
       
  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 *     +-----------------------+-----------+--------------------+
       
  1341 *
       
  1342 *  Value of column q in solution to the original problem is the same as
       
  1343 *  in solution to the transformed problem.
       
  1344 *
       
  1345 *  RECOVERING INTERIOR POINT SOLUTION
       
  1346 *
       
  1347 *  Value of column q in solution to the original problem is the same as
       
  1348 *  in solution to the transformed problem.
       
  1349 *
       
  1350 *  RECOVERING MIP SOLUTION
       
  1351 *
       
  1352 *  None needed. */
       
  1353 
       
  1354 struct make_fixed
       
  1355 {     /* column with almost identical bounds */
       
  1356       int q;
       
  1357       /* column reference number */
       
  1358       double c;
       
  1359       /* objective coefficient at x[q] */
       
  1360       NPPLFE *ptr;
       
  1361       /* list of non-zero coefficients a[i,q] */
       
  1362 };
       
  1363 
       
  1364 static int rcv_make_fixed(NPP *npp, void *info);
       
  1365 
       
  1366 int npp_make_fixed(NPP *npp, NPPCOL *q)
       
  1367 {     /* process column with almost identical bounds */
       
  1368       struct make_fixed *info;
       
  1369       NPPAIJ *aij;
       
  1370       NPPLFE *lfe;
       
  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));
       
  1383       info->q = q->j;
       
  1384       info->c = q->coef;
       
  1385       info->ptr = NULL;
       
  1386       /* save column coefficients a[i,q] (needed for basic solution
       
  1387          only) */
       
  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;
       
  1394             info->ptr = lfe;
       
  1395          }
       
  1396       }
       
  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 */
       
  1402       q->lb = q->ub = s;
       
  1403       return 1;
       
  1404 }
       
  1405 
       
  1406 static int rcv_make_fixed(NPP *npp, void *_info)
       
  1407 {     /* recover column with almost identical bounds */
       
  1408       struct make_fixed *info = _info;
       
  1409       NPPLFE *lfe;
       
  1410       double lambda;
       
  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) */
       
  1416             lambda = info->c;
       
  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 */
       
  1420             if (lambda >= 0.0)
       
  1421                npp->c_stat[info->q] = GLP_NL;
       
  1422             else
       
  1423                npp->c_stat[info->q] = GLP_NU;
       
  1424          }
       
  1425          else
       
  1426          {  npp_error();
       
  1427             return 1;
       
  1428          }
       
  1429       }
       
  1430       return 0;
       
  1431 }
       
  1432 
       
  1433 /* eof */