src/glpnpp02.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpnpp02.c */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#include "glpnpp.h"
alpar@1
    26
alpar@1
    27
/***********************************************************************
alpar@1
    28
*  NAME
alpar@1
    29
*
alpar@1
    30
*  npp_free_row - process free (unbounded) row
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  #include "glpnpp.h"
alpar@1
    35
*  void npp_free_row(NPP *npp, NPPROW *p);
alpar@1
    36
*
alpar@1
    37
*  DESCRIPTION
alpar@1
    38
*
alpar@1
    39
*  The routine npp_free_row processes row p, which is free (i.e. has
alpar@1
    40
*  no finite bounds):
alpar@1
    41
*
alpar@1
    42
*     -inf < sum a[p,j] x[j] < +inf.                                 (1)
alpar@1
    43
*             j
alpar@1
    44
*
alpar@1
    45
*  PROBLEM TRANSFORMATION
alpar@1
    46
*
alpar@1
    47
*  Constraint (1) cannot be active, so it is redundant and can be
alpar@1
    48
*  removed from the original problem.
alpar@1
    49
*
alpar@1
    50
*  Removing row p leads to removing a column of multiplier pi[p] for
alpar@1
    51
*  this row in the dual system. Since row p has no bounds, pi[p] = 0,
alpar@1
    52
*  so removing the column does not affect the dual solution.
alpar@1
    53
*
alpar@1
    54
*  RECOVERING BASIC SOLUTION
alpar@1
    55
*
alpar@1
    56
*  In solution to the original problem row p is inactive constraint,
alpar@1
    57
*  so it is assigned status GLP_BS, and multiplier pi[p] is assigned
alpar@1
    58
*  zero value.
alpar@1
    59
*
alpar@1
    60
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
    61
*
alpar@1
    62
*  In solution to the original problem row p is inactive constraint,
alpar@1
    63
*  so its multiplier pi[p] is assigned zero value.
alpar@1
    64
*
alpar@1
    65
*  RECOVERING MIP SOLUTION
alpar@1
    66
*
alpar@1
    67
*  None needed. */
alpar@1
    68
alpar@1
    69
struct free_row
alpar@1
    70
{     /* free (unbounded) row */
alpar@1
    71
      int p;
alpar@1
    72
      /* row reference number */
alpar@1
    73
};
alpar@1
    74
alpar@1
    75
static int rcv_free_row(NPP *npp, void *info);
alpar@1
    76
alpar@1
    77
void npp_free_row(NPP *npp, NPPROW *p)
alpar@1
    78
{     /* process free (unbounded) row */
alpar@1
    79
      struct free_row *info;
alpar@1
    80
      /* the row must be free */
alpar@1
    81
      xassert(p->lb == -DBL_MAX && p->ub == +DBL_MAX);
alpar@1
    82
      /* create transformation stack entry */
alpar@1
    83
      info = npp_push_tse(npp,
alpar@1
    84
         rcv_free_row, sizeof(struct free_row));
alpar@1
    85
      info->p = p->i;
alpar@1
    86
      /* remove the row from the problem */
alpar@1
    87
      npp_del_row(npp, p);
alpar@1
    88
      return;
alpar@1
    89
}
alpar@1
    90
alpar@1
    91
static int rcv_free_row(NPP *npp, void *_info)
alpar@1
    92
{     /* recover free (unbounded) row */
alpar@1
    93
      struct free_row *info = _info;
alpar@1
    94
      if (npp->sol == GLP_SOL)
alpar@1
    95
         npp->r_stat[info->p] = GLP_BS;
alpar@1
    96
      if (npp->sol != GLP_MIP)
alpar@1
    97
         npp->r_pi[info->p] = 0.0;
alpar@1
    98
      return 0;
alpar@1
    99
}
alpar@1
   100
alpar@1
   101
/***********************************************************************
alpar@1
   102
*  NAME
alpar@1
   103
*
alpar@1
   104
*  npp_geq_row - process row of 'not less than' type
alpar@1
   105
*
alpar@1
   106
*  SYNOPSIS
alpar@1
   107
*
alpar@1
   108
*  #include "glpnpp.h"
alpar@1
   109
*  void npp_geq_row(NPP *npp, NPPROW *p);
alpar@1
   110
*
alpar@1
   111
*  DESCRIPTION
alpar@1
   112
*
alpar@1
   113
*  The routine npp_geq_row processes row p, which is 'not less than'
alpar@1
   114
*  inequality constraint:
alpar@1
   115
*
alpar@1
   116
*     L[p] <= sum a[p,j] x[j] (<= U[p]),                             (1)
alpar@1
   117
*              j
alpar@1
   118
*
alpar@1
   119
*  where L[p] < U[p], and upper bound may not exist (U[p] = +oo).
alpar@1
   120
*
alpar@1
   121
*  PROBLEM TRANSFORMATION
alpar@1
   122
*
alpar@1
   123
*  Constraint (1) can be replaced by equality constraint:
alpar@1
   124
*
alpar@1
   125
*     sum a[p,j] x[j] - s = L[p],                                    (2)
alpar@1
   126
*      j
alpar@1
   127
*
alpar@1
   128
*  where
alpar@1
   129
*
alpar@1
   130
*     0 <= s (<= U[p] - L[p])                                        (3)
alpar@1
   131
*
alpar@1
   132
*  is a non-negative surplus variable.
alpar@1
   133
*
alpar@1
   134
*  Since in the primal system there appears column s having the only
alpar@1
   135
*  non-zero coefficient in row p, in the dual system there appears a
alpar@1
   136
*  new row:
alpar@1
   137
*
alpar@1
   138
*     (-1) pi[p] + lambda = 0,                                       (4)
alpar@1
   139
*
alpar@1
   140
*  where (-1) is coefficient of column s in row p, pi[p] is multiplier
alpar@1
   141
*  of row p, lambda is multiplier of column q, 0 is coefficient of
alpar@1
   142
*  column s in the objective row.
alpar@1
   143
*
alpar@1
   144
*  RECOVERING BASIC SOLUTION
alpar@1
   145
*
alpar@1
   146
*  Status of row p in solution to the original problem is determined
alpar@1
   147
*  by its status and status of column q in solution to the transformed
alpar@1
   148
*  problem as follows:
alpar@1
   149
*
alpar@1
   150
*     +--------------------------------------+------------------+
alpar@1
   151
*     |         Transformed problem          | Original problem |
alpar@1
   152
*     +-----------------+--------------------+------------------+
alpar@1
   153
*     | Status of row p | Status of column s | Status of row p  |
alpar@1
   154
*     +-----------------+--------------------+------------------+
alpar@1
   155
*     |     GLP_BS      |       GLP_BS       |       N/A        |
alpar@1
   156
*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
alpar@1
   157
*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
alpar@1
   158
*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
alpar@1
   159
*     |     GLP_NS      |       GLP_NL       |      GLP_NL      |
alpar@1
   160
*     |     GLP_NS      |       GLP_NU       |      GLP_NU      |
alpar@1
   161
*     +-----------------+--------------------+------------------+
alpar@1
   162
*
alpar@1
   163
*  Value of row multiplier pi[p] in solution to the original problem
alpar@1
   164
*  is the same as in solution to the transformed problem.
alpar@1
   165
*
alpar@1
   166
*  1. In solution to the transformed problem row p and column q cannot
alpar@1
   167
*     be basic at the same time; otherwise the basis matrix would have
alpar@1
   168
*     two linear dependent columns: unity column of auxiliary variable
alpar@1
   169
*     of row p and unity column of variable s.
alpar@1
   170
*
alpar@1
   171
*  2. Though in the transformed problem row p is equality constraint,
alpar@1
   172
*     it may be basic due to primal degenerate solution.
alpar@1
   173
*
alpar@1
   174
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   175
*
alpar@1
   176
*  Value of row multiplier pi[p] in solution to the original problem
alpar@1
   177
*  is the same as in solution to the transformed problem.
alpar@1
   178
*
alpar@1
   179
*  RECOVERING MIP SOLUTION
alpar@1
   180
*
alpar@1
   181
*  None needed. */
alpar@1
   182
alpar@1
   183
struct ineq_row
alpar@1
   184
{     /* inequality constraint row */
alpar@1
   185
      int p;
alpar@1
   186
      /* row reference number */
alpar@1
   187
      int s;
alpar@1
   188
      /* column reference number for slack/surplus variable */
alpar@1
   189
};
alpar@1
   190
alpar@1
   191
static int rcv_geq_row(NPP *npp, void *info);
alpar@1
   192
alpar@1
   193
void npp_geq_row(NPP *npp, NPPROW *p)
alpar@1
   194
{     /* process row of 'not less than' type */
alpar@1
   195
      struct ineq_row *info;
alpar@1
   196
      NPPCOL *s;
alpar@1
   197
      /* the row must have lower bound */
alpar@1
   198
      xassert(p->lb != -DBL_MAX);
alpar@1
   199
      xassert(p->lb < p->ub);
alpar@1
   200
      /* create column for surplus variable */
alpar@1
   201
      s = npp_add_col(npp);
alpar@1
   202
      s->lb = 0.0;
alpar@1
   203
      s->ub = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub - p->lb);
alpar@1
   204
      /* and add it to the transformed problem */
alpar@1
   205
      npp_add_aij(npp, p, s, -1.0);
alpar@1
   206
      /* create transformation stack entry */
alpar@1
   207
      info = npp_push_tse(npp,
alpar@1
   208
         rcv_geq_row, sizeof(struct ineq_row));
alpar@1
   209
      info->p = p->i;
alpar@1
   210
      info->s = s->j;
alpar@1
   211
      /* replace the row by equality constraint */
alpar@1
   212
      p->ub = p->lb;
alpar@1
   213
      return;
alpar@1
   214
}
alpar@1
   215
alpar@1
   216
static int rcv_geq_row(NPP *npp, void *_info)
alpar@1
   217
{     /* recover row of 'not less than' type */
alpar@1
   218
      struct ineq_row *info = _info;
alpar@1
   219
      if (npp->sol == GLP_SOL)
alpar@1
   220
      {  if (npp->r_stat[info->p] == GLP_BS)
alpar@1
   221
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   222
            {  npp_error();
alpar@1
   223
               return 1;
alpar@1
   224
            }
alpar@1
   225
            else if (npp->c_stat[info->s] == GLP_NL ||
alpar@1
   226
                     npp->c_stat[info->s] == GLP_NU)
alpar@1
   227
               npp->r_stat[info->p] = GLP_BS;
alpar@1
   228
            else
alpar@1
   229
            {  npp_error();
alpar@1
   230
               return 1;
alpar@1
   231
            }
alpar@1
   232
         }
alpar@1
   233
         else if (npp->r_stat[info->p] == GLP_NS)
alpar@1
   234
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   235
               npp->r_stat[info->p] = GLP_BS;
alpar@1
   236
            else if (npp->c_stat[info->s] == GLP_NL)
alpar@1
   237
               npp->r_stat[info->p] = GLP_NL;
alpar@1
   238
            else if (npp->c_stat[info->s] == GLP_NU)
alpar@1
   239
               npp->r_stat[info->p] = GLP_NU;
alpar@1
   240
            else
alpar@1
   241
            {  npp_error();
alpar@1
   242
               return 1;
alpar@1
   243
            }
alpar@1
   244
         }
alpar@1
   245
         else
alpar@1
   246
         {  npp_error();
alpar@1
   247
            return 1;
alpar@1
   248
         }
alpar@1
   249
      }
alpar@1
   250
      return 0;
alpar@1
   251
}
alpar@1
   252
alpar@1
   253
/***********************************************************************
alpar@1
   254
*  NAME
alpar@1
   255
*
alpar@1
   256
*  npp_leq_row - process row of 'not greater than' type
alpar@1
   257
*
alpar@1
   258
*  SYNOPSIS
alpar@1
   259
*
alpar@1
   260
*  #include "glpnpp.h"
alpar@1
   261
*  void npp_leq_row(NPP *npp, NPPROW *p);
alpar@1
   262
*
alpar@1
   263
*  DESCRIPTION
alpar@1
   264
*
alpar@1
   265
*  The routine npp_leq_row processes row p, which is 'not greater than'
alpar@1
   266
*  inequality constraint:
alpar@1
   267
*
alpar@1
   268
*     (L[p] <=) sum a[p,j] x[j] <= U[p],                             (1)
alpar@1
   269
*                j
alpar@1
   270
*
alpar@1
   271
*  where L[p] < U[p], and lower bound may not exist (L[p] = +oo).
alpar@1
   272
*
alpar@1
   273
*  PROBLEM TRANSFORMATION
alpar@1
   274
*
alpar@1
   275
*  Constraint (1) can be replaced by equality constraint:
alpar@1
   276
*
alpar@1
   277
*     sum a[p,j] x[j] + s = L[p],                                    (2)
alpar@1
   278
*      j
alpar@1
   279
*
alpar@1
   280
*  where
alpar@1
   281
*
alpar@1
   282
*     0 <= s (<= U[p] - L[p])                                        (3)
alpar@1
   283
*
alpar@1
   284
*  is a non-negative slack variable.
alpar@1
   285
*
alpar@1
   286
*  Since in the primal system there appears column s having the only
alpar@1
   287
*  non-zero coefficient in row p, in the dual system there appears a
alpar@1
   288
*  new row:
alpar@1
   289
*
alpar@1
   290
*     (+1) pi[p] + lambda = 0,                                       (4)
alpar@1
   291
*
alpar@1
   292
*  where (+1) is coefficient of column s in row p, pi[p] is multiplier
alpar@1
   293
*  of row p, lambda is multiplier of column q, 0 is coefficient of
alpar@1
   294
*  column s in the objective row.
alpar@1
   295
*
alpar@1
   296
*  RECOVERING BASIC SOLUTION
alpar@1
   297
*
alpar@1
   298
*  Status of row p in solution to the original problem is determined
alpar@1
   299
*  by its status and status of column q in solution to the transformed
alpar@1
   300
*  problem as follows:
alpar@1
   301
*
alpar@1
   302
*     +--------------------------------------+------------------+
alpar@1
   303
*     |         Transformed problem          | Original problem |
alpar@1
   304
*     +-----------------+--------------------+------------------+
alpar@1
   305
*     | Status of row p | Status of column s | Status of row p  |
alpar@1
   306
*     +-----------------+--------------------+------------------+
alpar@1
   307
*     |     GLP_BS      |       GLP_BS       |       N/A        |
alpar@1
   308
*     |     GLP_BS      |       GLP_NL       |      GLP_BS      |
alpar@1
   309
*     |     GLP_BS      |       GLP_NU       |      GLP_BS      |
alpar@1
   310
*     |     GLP_NS      |       GLP_BS       |      GLP_BS      |
alpar@1
   311
*     |     GLP_NS      |       GLP_NL       |      GLP_NU      |
alpar@1
   312
*     |     GLP_NS      |       GLP_NU       |      GLP_NL      |
alpar@1
   313
*     +-----------------+--------------------+------------------+
alpar@1
   314
*
alpar@1
   315
*  Value of row multiplier pi[p] in solution to the original problem
alpar@1
   316
*  is the same as in solution to the transformed problem.
alpar@1
   317
*
alpar@1
   318
*  1. In solution to the transformed problem row p and column q cannot
alpar@1
   319
*     be basic at the same time; otherwise the basis matrix would have
alpar@1
   320
*     two linear dependent columns: unity column of auxiliary variable
alpar@1
   321
*     of row p and unity column of variable s.
alpar@1
   322
*
alpar@1
   323
*  2. Though in the transformed problem row p is equality constraint,
alpar@1
   324
*     it may be basic due to primal degeneracy.
alpar@1
   325
*
alpar@1
   326
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   327
*
alpar@1
   328
*  Value of row multiplier pi[p] in solution to the original problem
alpar@1
   329
*  is the same as in solution to the transformed problem.
alpar@1
   330
*
alpar@1
   331
*  RECOVERING MIP SOLUTION
alpar@1
   332
*
alpar@1
   333
*  None needed. */
alpar@1
   334
alpar@1
   335
static int rcv_leq_row(NPP *npp, void *info);
alpar@1
   336
alpar@1
   337
void npp_leq_row(NPP *npp, NPPROW *p)
alpar@1
   338
{     /* process row of 'not greater than' type */
alpar@1
   339
      struct ineq_row *info;
alpar@1
   340
      NPPCOL *s;
alpar@1
   341
      /* the row must have upper bound */
alpar@1
   342
      xassert(p->ub != +DBL_MAX);
alpar@1
   343
      xassert(p->lb < p->ub);
alpar@1
   344
      /* create column for slack variable */
alpar@1
   345
      s = npp_add_col(npp);
alpar@1
   346
      s->lb = 0.0;
alpar@1
   347
      s->ub = (p->lb == -DBL_MAX ? +DBL_MAX : p->ub - p->lb);
alpar@1
   348
      /* and add it to the transformed problem */
alpar@1
   349
      npp_add_aij(npp, p, s, +1.0);
alpar@1
   350
      /* create transformation stack entry */
alpar@1
   351
      info = npp_push_tse(npp,
alpar@1
   352
         rcv_leq_row, sizeof(struct ineq_row));
alpar@1
   353
      info->p = p->i;
alpar@1
   354
      info->s = s->j;
alpar@1
   355
      /* replace the row by equality constraint */
alpar@1
   356
      p->lb = p->ub;
alpar@1
   357
      return;
alpar@1
   358
}
alpar@1
   359
alpar@1
   360
static int rcv_leq_row(NPP *npp, void *_info)
alpar@1
   361
{     /* recover row of 'not greater than' type */
alpar@1
   362
      struct ineq_row *info = _info;
alpar@1
   363
      if (npp->sol == GLP_SOL)
alpar@1
   364
      {  if (npp->r_stat[info->p] == GLP_BS)
alpar@1
   365
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   366
            {  npp_error();
alpar@1
   367
               return 1;
alpar@1
   368
            }
alpar@1
   369
            else if (npp->c_stat[info->s] == GLP_NL ||
alpar@1
   370
                     npp->c_stat[info->s] == GLP_NU)
alpar@1
   371
               npp->r_stat[info->p] = GLP_BS;
alpar@1
   372
            else
alpar@1
   373
            {  npp_error();
alpar@1
   374
               return 1;
alpar@1
   375
            }
alpar@1
   376
         }
alpar@1
   377
         else if (npp->r_stat[info->p] == GLP_NS)
alpar@1
   378
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   379
               npp->r_stat[info->p] = GLP_BS;
alpar@1
   380
            else if (npp->c_stat[info->s] == GLP_NL)
alpar@1
   381
               npp->r_stat[info->p] = GLP_NU;
alpar@1
   382
            else if (npp->c_stat[info->s] == GLP_NU)
alpar@1
   383
               npp->r_stat[info->p] = GLP_NL;
alpar@1
   384
            else
alpar@1
   385
            {  npp_error();
alpar@1
   386
               return 1;
alpar@1
   387
            }
alpar@1
   388
         }
alpar@1
   389
         else
alpar@1
   390
         {  npp_error();
alpar@1
   391
            return 1;
alpar@1
   392
         }
alpar@1
   393
      }
alpar@1
   394
      return 0;
alpar@1
   395
}
alpar@1
   396
alpar@1
   397
/***********************************************************************
alpar@1
   398
*  NAME
alpar@1
   399
*
alpar@1
   400
*  npp_free_col - process free (unbounded) column
alpar@1
   401
*
alpar@1
   402
*  SYNOPSIS
alpar@1
   403
*
alpar@1
   404
*  #include "glpnpp.h"
alpar@1
   405
*  void npp_free_col(NPP *npp, NPPCOL *q);
alpar@1
   406
*
alpar@1
   407
*  DESCRIPTION
alpar@1
   408
*
alpar@1
   409
*  The routine npp_free_col processes column q, which is free (i.e. has
alpar@1
   410
*  no finite bounds):
alpar@1
   411
*
alpar@1
   412
*     -oo < x[q] < +oo.                                              (1)
alpar@1
   413
*
alpar@1
   414
*  PROBLEM TRANSFORMATION
alpar@1
   415
*
alpar@1
   416
*  Free (unbounded) variable can be replaced by the difference of two
alpar@1
   417
*  non-negative variables:
alpar@1
   418
*
alpar@1
   419
*     x[q] = s' - s'',   s', s'' >= 0.                               (2)
alpar@1
   420
*
alpar@1
   421
*  Assuming that in the transformed problem x[q] becomes s',
alpar@1
   422
*  transformation (2) causes new column s'' to appear, which differs
alpar@1
   423
*  from column s' only in the sign of coefficients in constraint and
alpar@1
   424
*  objective rows. Thus, if in the dual system the following row
alpar@1
   425
*  corresponds to column s':
alpar@1
   426
*
alpar@1
   427
*     sum a[i,q] pi[i] + lambda' = c[q],                             (3)
alpar@1
   428
*      i
alpar@1
   429
*
alpar@1
   430
*  the row which corresponds to column s'' is the following:
alpar@1
   431
*
alpar@1
   432
*     sum (-a[i,q]) pi[i] + lambda'' = -c[q].                        (4)
alpar@1
   433
*      i
alpar@1
   434
*
alpar@1
   435
*  Then from (3) and (4) it follows that:
alpar@1
   436
*
alpar@1
   437
*     lambda' + lambda'' = 0   =>   lambda' = lmabda'' = 0,          (5)
alpar@1
   438
*
alpar@1
   439
*  where lambda' and lambda'' are multipliers for columns s' and s'',
alpar@1
   440
*  resp.
alpar@1
   441
*
alpar@1
   442
*  RECOVERING BASIC SOLUTION
alpar@1
   443
*
alpar@1
   444
*  With respect to (5) status of column q in solution to the original
alpar@1
   445
*  problem is determined by statuses of columns s' and s'' in solution
alpar@1
   446
*  to the transformed problem as follows:
alpar@1
   447
*
alpar@1
   448
*     +--------------------------------------+------------------+
alpar@1
   449
*     |         Transformed problem          | Original problem |
alpar@1
   450
*     +------------------+-------------------+------------------+
alpar@1
   451
*     | Status of col s' | Status of col s'' | Status of col q  |
alpar@1
   452
*     +------------------+-------------------+------------------+
alpar@1
   453
*     |      GLP_BS      |      GLP_BS       |       N/A        |
alpar@1
   454
*     |      GLP_BS      |      GLP_NL       |      GLP_BS      |
alpar@1
   455
*     |      GLP_NL      |      GLP_BS       |      GLP_BS      |
alpar@1
   456
*     |      GLP_NL      |      GLP_NL       |      GLP_NF      |
alpar@1
   457
*     +------------------+-------------------+------------------+
alpar@1
   458
*
alpar@1
   459
*  Value of column q is computed with formula (2).
alpar@1
   460
*
alpar@1
   461
*  1. In solution to the transformed problem columns s' and s'' cannot
alpar@1
   462
*     be basic at the same time, because they differ only in the sign,
alpar@1
   463
*     hence, are linear dependent.
alpar@1
   464
*
alpar@1
   465
*  2. Though column q is free, it can be non-basic due to dual
alpar@1
   466
*     degeneracy.
alpar@1
   467
*
alpar@1
   468
*  3. If column q is integral, columns s' and s'' are also integral.
alpar@1
   469
*
alpar@1
   470
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   471
*
alpar@1
   472
*  Value of column q is computed with formula (2).
alpar@1
   473
*
alpar@1
   474
*  RECOVERING MIP SOLUTION
alpar@1
   475
*
alpar@1
   476
*  Value of column q is computed with formula (2). */
alpar@1
   477
alpar@1
   478
struct free_col
alpar@1
   479
{     /* free (unbounded) column */
alpar@1
   480
      int q;
alpar@1
   481
      /* column reference number for variables x[q] and s' */
alpar@1
   482
      int s;
alpar@1
   483
      /* column reference number for variable s'' */
alpar@1
   484
};
alpar@1
   485
alpar@1
   486
static int rcv_free_col(NPP *npp, void *info);
alpar@1
   487
alpar@1
   488
void npp_free_col(NPP *npp, NPPCOL *q)
alpar@1
   489
{     /* process free (unbounded) column */
alpar@1
   490
      struct free_col *info;
alpar@1
   491
      NPPCOL *s;
alpar@1
   492
      NPPAIJ *aij;
alpar@1
   493
      /* the column must be free */
alpar@1
   494
      xassert(q->lb == -DBL_MAX && q->ub == +DBL_MAX);
alpar@1
   495
      /* variable x[q] becomes s' */
alpar@1
   496
      q->lb = 0.0, q->ub = +DBL_MAX;
alpar@1
   497
      /* create variable s'' */
alpar@1
   498
      s = npp_add_col(npp);
alpar@1
   499
      s->is_int = q->is_int;
alpar@1
   500
      s->lb = 0.0, s->ub = +DBL_MAX;
alpar@1
   501
      /* duplicate objective coefficient */
alpar@1
   502
      s->coef = -q->coef;
alpar@1
   503
      /* duplicate column of the constraint matrix */
alpar@1
   504
      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   505
         npp_add_aij(npp, aij->row, s, -aij->val);
alpar@1
   506
      /* create transformation stack entry */
alpar@1
   507
      info = npp_push_tse(npp,
alpar@1
   508
         rcv_free_col, sizeof(struct free_col));
alpar@1
   509
      info->q = q->j;
alpar@1
   510
      info->s = s->j;
alpar@1
   511
      return;
alpar@1
   512
}
alpar@1
   513
alpar@1
   514
static int rcv_free_col(NPP *npp, void *_info)
alpar@1
   515
{     /* recover free (unbounded) column */
alpar@1
   516
      struct free_col *info = _info;
alpar@1
   517
      if (npp->sol == GLP_SOL)
alpar@1
   518
      {  if (npp->c_stat[info->q] == GLP_BS)
alpar@1
   519
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   520
            {  npp_error();
alpar@1
   521
               return 1;
alpar@1
   522
            }
alpar@1
   523
            else if (npp->c_stat[info->s] == GLP_NL)
alpar@1
   524
               npp->c_stat[info->q] = GLP_BS;
alpar@1
   525
            else
alpar@1
   526
            {  npp_error();
alpar@1
   527
               return -1;
alpar@1
   528
            }
alpar@1
   529
         }
alpar@1
   530
         else if (npp->c_stat[info->q] == GLP_NL)
alpar@1
   531
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   532
               npp->c_stat[info->q] = GLP_BS;
alpar@1
   533
            else if (npp->c_stat[info->s] == GLP_NL)
alpar@1
   534
               npp->c_stat[info->q] = GLP_NF;
alpar@1
   535
            else
alpar@1
   536
            {  npp_error();
alpar@1
   537
               return -1;
alpar@1
   538
            }
alpar@1
   539
         }
alpar@1
   540
         else
alpar@1
   541
         {  npp_error();
alpar@1
   542
            return -1;
alpar@1
   543
         }
alpar@1
   544
      }
alpar@1
   545
      /* compute value of x[q] with formula (2) */
alpar@1
   546
      npp->c_value[info->q] -= npp->c_value[info->s];
alpar@1
   547
      return 0;
alpar@1
   548
}
alpar@1
   549
alpar@1
   550
/***********************************************************************
alpar@1
   551
*  NAME
alpar@1
   552
*
alpar@1
   553
*  npp_lbnd_col - process column with (non-zero) lower bound
alpar@1
   554
*
alpar@1
   555
*  SYNOPSIS
alpar@1
   556
*
alpar@1
   557
*  #include "glpnpp.h"
alpar@1
   558
*  void npp_lbnd_col(NPP *npp, NPPCOL *q);
alpar@1
   559
*
alpar@1
   560
*  DESCRIPTION
alpar@1
   561
*
alpar@1
   562
*  The routine npp_lbnd_col processes column q, which has (non-zero)
alpar@1
   563
*  lower bound:
alpar@1
   564
*
alpar@1
   565
*     l[q] <= x[q] (<= u[q]),                                        (1)
alpar@1
   566
*
alpar@1
   567
*  where l[q] < u[q], and upper bound may not exist (u[q] = +oo).
alpar@1
   568
*
alpar@1
   569
*  PROBLEM TRANSFORMATION
alpar@1
   570
*
alpar@1
   571
*  Column q can be replaced as follows:
alpar@1
   572
*
alpar@1
   573
*     x[q] = l[q] + s,                                               (2)
alpar@1
   574
*
alpar@1
   575
*  where
alpar@1
   576
*
alpar@1
   577
*     0 <= s (<= u[q] - l[q])                                        (3)
alpar@1
   578
*
alpar@1
   579
*  is a non-negative variable.
alpar@1
   580
*
alpar@1
   581
*  Substituting x[q] from (2) into the objective row, we have:
alpar@1
   582
*
alpar@1
   583
*     z = sum c[j] x[j] + c0 =
alpar@1
   584
*          j
alpar@1
   585
*
alpar@1
   586
*       = sum c[j] x[j] + c[q] x[q] + c0 =
alpar@1
   587
*         j!=q
alpar@1
   588
*
alpar@1
   589
*       = sum c[j] x[j] + c[q] (l[q] + s) + c0 =
alpar@1
   590
*         j!=q
alpar@1
   591
*
alpar@1
   592
*       = sum c[j] x[j] + c[q] s + c~0,
alpar@1
   593
*
alpar@1
   594
*  where
alpar@1
   595
*
alpar@1
   596
*     c~0 = c0 + c[q] l[q]                                           (4)
alpar@1
   597
*
alpar@1
   598
*  is the constant term of the objective in the transformed problem.
alpar@1
   599
*  Similarly, substituting x[q] into constraint row i, we have:
alpar@1
   600
*
alpar@1
   601
*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
alpar@1
   602
*              j
alpar@1
   603
*
alpar@1
   604
*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
alpar@1
   605
*             j!=q
alpar@1
   606
*
alpar@1
   607
*     L[i] <= sum a[i,j] x[j] + a[i,q] (l[q] + s) <= U[i]  ==>
alpar@1
   608
*             j!=q
alpar@1
   609
*
alpar@1
   610
*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
alpar@1
   611
*              j!=q
alpar@1
   612
*
alpar@1
   613
*  where
alpar@1
   614
*
alpar@1
   615
*     L~[i] = L[i] - a[i,q] l[q],  U~[i] = U[i] - a[i,q] l[q]        (5)
alpar@1
   616
*
alpar@1
   617
*  are lower and upper bounds of row i in the transformed problem,
alpar@1
   618
*  resp.
alpar@1
   619
*
alpar@1
   620
*  Transformation (2) does not affect the dual system.
alpar@1
   621
*
alpar@1
   622
*  RECOVERING BASIC SOLUTION
alpar@1
   623
*
alpar@1
   624
*  Status of column q in solution to the original problem is the same
alpar@1
   625
*  as in solution to the transformed problem (GLP_BS, GLP_NL or GLP_NU).
alpar@1
   626
*  Value of column q is computed with formula (2).
alpar@1
   627
*
alpar@1
   628
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   629
*
alpar@1
   630
*  Value of column q is computed with formula (2).
alpar@1
   631
*
alpar@1
   632
*  RECOVERING MIP SOLUTION
alpar@1
   633
*
alpar@1
   634
*  Value of column q is computed with formula (2). */
alpar@1
   635
alpar@1
   636
struct bnd_col
alpar@1
   637
{     /* bounded column */
alpar@1
   638
      int q;
alpar@1
   639
      /* column reference number for variables x[q] and s */
alpar@1
   640
      double bnd;
alpar@1
   641
      /* lower/upper bound l[q] or u[q] */
alpar@1
   642
};
alpar@1
   643
alpar@1
   644
static int rcv_lbnd_col(NPP *npp, void *info);
alpar@1
   645
alpar@1
   646
void npp_lbnd_col(NPP *npp, NPPCOL *q)
alpar@1
   647
{     /* process column with (non-zero) lower bound */
alpar@1
   648
      struct bnd_col *info;
alpar@1
   649
      NPPROW *i;
alpar@1
   650
      NPPAIJ *aij;
alpar@1
   651
      /* the column must have non-zero lower bound */
alpar@1
   652
      xassert(q->lb != 0.0);
alpar@1
   653
      xassert(q->lb != -DBL_MAX);
alpar@1
   654
      xassert(q->lb < q->ub);
alpar@1
   655
      /* create transformation stack entry */
alpar@1
   656
      info = npp_push_tse(npp,
alpar@1
   657
         rcv_lbnd_col, sizeof(struct bnd_col));
alpar@1
   658
      info->q = q->j;
alpar@1
   659
      info->bnd = q->lb;
alpar@1
   660
      /* substitute x[q] into objective row */
alpar@1
   661
      npp->c0 += q->coef * q->lb;
alpar@1
   662
      /* substitute x[q] into constraint rows */
alpar@1
   663
      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   664
      {  i = aij->row;
alpar@1
   665
         if (i->lb == i->ub)
alpar@1
   666
            i->ub = (i->lb -= aij->val * q->lb);
alpar@1
   667
         else
alpar@1
   668
         {  if (i->lb != -DBL_MAX)
alpar@1
   669
               i->lb -= aij->val * q->lb;
alpar@1
   670
            if (i->ub != +DBL_MAX)
alpar@1
   671
               i->ub -= aij->val * q->lb;
alpar@1
   672
         }
alpar@1
   673
      }
alpar@1
   674
      /* column x[q] becomes column s */
alpar@1
   675
      if (q->ub != +DBL_MAX)
alpar@1
   676
         q->ub -= q->lb;
alpar@1
   677
      q->lb = 0.0;
alpar@1
   678
      return;
alpar@1
   679
}
alpar@1
   680
alpar@1
   681
static int rcv_lbnd_col(NPP *npp, void *_info)
alpar@1
   682
{     /* recover column with (non-zero) lower bound */
alpar@1
   683
      struct bnd_col *info = _info;
alpar@1
   684
      if (npp->sol == GLP_SOL)
alpar@1
   685
      {  if (npp->c_stat[info->q] == GLP_BS ||
alpar@1
   686
             npp->c_stat[info->q] == GLP_NL ||
alpar@1
   687
             npp->c_stat[info->q] == GLP_NU)
alpar@1
   688
            npp->c_stat[info->q] = npp->c_stat[info->q];
alpar@1
   689
         else
alpar@1
   690
         {  npp_error();
alpar@1
   691
            return 1;
alpar@1
   692
         }
alpar@1
   693
      }
alpar@1
   694
      /* compute value of x[q] with formula (2) */
alpar@1
   695
      npp->c_value[info->q] = info->bnd + npp->c_value[info->q];
alpar@1
   696
      return 0;
alpar@1
   697
}
alpar@1
   698
alpar@1
   699
/***********************************************************************
alpar@1
   700
*  NAME
alpar@1
   701
*
alpar@1
   702
*  npp_ubnd_col - process column with upper bound
alpar@1
   703
*
alpar@1
   704
*  SYNOPSIS
alpar@1
   705
*
alpar@1
   706
*  #include "glpnpp.h"
alpar@1
   707
*  void npp_ubnd_col(NPP *npp, NPPCOL *q);
alpar@1
   708
*
alpar@1
   709
*  DESCRIPTION
alpar@1
   710
*
alpar@1
   711
*  The routine npp_ubnd_col processes column q, which has upper bound:
alpar@1
   712
*
alpar@1
   713
*     (l[q] <=) x[q] <= u[q],                                        (1)
alpar@1
   714
*
alpar@1
   715
*  where l[q] < u[q], and lower bound may not exist (l[q] = -oo).
alpar@1
   716
*
alpar@1
   717
*  PROBLEM TRANSFORMATION
alpar@1
   718
*
alpar@1
   719
*  Column q can be replaced as follows:
alpar@1
   720
*
alpar@1
   721
*     x[q] = u[q] - s,                                               (2)
alpar@1
   722
*
alpar@1
   723
*  where
alpar@1
   724
*
alpar@1
   725
*     0 <= s (<= u[q] - l[q])                                        (3)
alpar@1
   726
*
alpar@1
   727
*  is a non-negative variable.
alpar@1
   728
*
alpar@1
   729
*  Substituting x[q] from (2) into the objective row, we have:
alpar@1
   730
*
alpar@1
   731
*     z = sum c[j] x[j] + c0 =
alpar@1
   732
*          j
alpar@1
   733
*
alpar@1
   734
*       = sum c[j] x[j] + c[q] x[q] + c0 =
alpar@1
   735
*         j!=q
alpar@1
   736
*
alpar@1
   737
*       = sum c[j] x[j] + c[q] (u[q] - s) + c0 =
alpar@1
   738
*         j!=q
alpar@1
   739
*
alpar@1
   740
*       = sum c[j] x[j] - c[q] s + c~0,
alpar@1
   741
*
alpar@1
   742
*  where
alpar@1
   743
*
alpar@1
   744
*     c~0 = c0 + c[q] u[q]                                           (4)
alpar@1
   745
*
alpar@1
   746
*  is the constant term of the objective in the transformed problem.
alpar@1
   747
*  Similarly, substituting x[q] into constraint row i, we have:
alpar@1
   748
*
alpar@1
   749
*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
alpar@1
   750
*              j
alpar@1
   751
*
alpar@1
   752
*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
alpar@1
   753
*             j!=q
alpar@1
   754
*
alpar@1
   755
*     L[i] <= sum a[i,j] x[j] + a[i,q] (u[q] - s) <= U[i]  ==>
alpar@1
   756
*             j!=q
alpar@1
   757
*
alpar@1
   758
*     L~[i] <= sum a[i,j] x[j] - a[i,q] s <= U~[i],
alpar@1
   759
*              j!=q
alpar@1
   760
*
alpar@1
   761
*  where
alpar@1
   762
*
alpar@1
   763
*     L~[i] = L[i] - a[i,q] u[q],  U~[i] = U[i] - a[i,q] u[q]        (5)
alpar@1
   764
*
alpar@1
   765
*  are lower and upper bounds of row i in the transformed problem,
alpar@1
   766
*  resp.
alpar@1
   767
*
alpar@1
   768
*  Note that in the transformed problem coefficients c[q] and a[i,q]
alpar@1
   769
*  change their sign. Thus, the row of the dual system corresponding to
alpar@1
   770
*  column q:
alpar@1
   771
*
alpar@1
   772
*     sum a[i,q] pi[i] + lambda[q] = c[q]                            (6)
alpar@1
   773
*      i
alpar@1
   774
*
alpar@1
   775
*  in the transformed problem becomes the following:
alpar@1
   776
*
alpar@1
   777
*     sum (-a[i,q]) pi[i] + lambda[s] = -c[q].                       (7)
alpar@1
   778
*      i
alpar@1
   779
*
alpar@1
   780
*  Therefore:
alpar@1
   781
*
alpar@1
   782
*     lambda[q] = - lambda[s],                                       (8)
alpar@1
   783
*
alpar@1
   784
*  where lambda[q] is multiplier for column q, lambda[s] is multiplier
alpar@1
   785
*  for column s.
alpar@1
   786
*
alpar@1
   787
*  RECOVERING BASIC SOLUTION
alpar@1
   788
*
alpar@1
   789
*  With respect to (8) status of column q in solution to the original
alpar@1
   790
*  problem is determined by status of column s in solution to the
alpar@1
   791
*  transformed problem as follows:
alpar@1
   792
*
alpar@1
   793
*     +-----------------------+--------------------+
alpar@1
   794
*     |  Status of column s   | Status of column q |
alpar@1
   795
*     | (transformed problem) | (original problem) |
alpar@1
   796
*     +-----------------------+--------------------+
alpar@1
   797
*     |        GLP_BS         |       GLP_BS       |
alpar@1
   798
*     |        GLP_NL         |       GLP_NU       |
alpar@1
   799
*     |        GLP_NU         |       GLP_NL       |
alpar@1
   800
*     +-----------------------+--------------------+
alpar@1
   801
*
alpar@1
   802
*  Value of column q is computed with formula (2).
alpar@1
   803
*
alpar@1
   804
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   805
*
alpar@1
   806
*  Value of column q is computed with formula (2).
alpar@1
   807
*
alpar@1
   808
*  RECOVERING MIP SOLUTION
alpar@1
   809
*
alpar@1
   810
*  Value of column q is computed with formula (2). */
alpar@1
   811
alpar@1
   812
static int rcv_ubnd_col(NPP *npp, void *info);
alpar@1
   813
alpar@1
   814
void npp_ubnd_col(NPP *npp, NPPCOL *q)
alpar@1
   815
{     /* process column with upper bound */
alpar@1
   816
      struct bnd_col *info;
alpar@1
   817
      NPPROW *i;
alpar@1
   818
      NPPAIJ *aij;
alpar@1
   819
      /* the column must have upper bound */
alpar@1
   820
      xassert(q->ub != +DBL_MAX);
alpar@1
   821
      xassert(q->lb < q->ub);
alpar@1
   822
      /* create transformation stack entry */
alpar@1
   823
      info = npp_push_tse(npp,
alpar@1
   824
         rcv_ubnd_col, sizeof(struct bnd_col));
alpar@1
   825
      info->q = q->j;
alpar@1
   826
      info->bnd = q->ub;
alpar@1
   827
      /* substitute x[q] into objective row */
alpar@1
   828
      npp->c0 += q->coef * q->ub;
alpar@1
   829
      q->coef = -q->coef;
alpar@1
   830
      /* substitute x[q] into constraint rows */
alpar@1
   831
      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   832
      {  i = aij->row;
alpar@1
   833
         if (i->lb == i->ub)
alpar@1
   834
            i->ub = (i->lb -= aij->val * q->ub);
alpar@1
   835
         else
alpar@1
   836
         {  if (i->lb != -DBL_MAX)
alpar@1
   837
               i->lb -= aij->val * q->ub;
alpar@1
   838
            if (i->ub != +DBL_MAX)
alpar@1
   839
               i->ub -= aij->val * q->ub;
alpar@1
   840
         }
alpar@1
   841
         aij->val = -aij->val;
alpar@1
   842
      }
alpar@1
   843
      /* column x[q] becomes column s */
alpar@1
   844
      if (q->lb != -DBL_MAX)
alpar@1
   845
         q->ub -= q->lb;
alpar@1
   846
      else
alpar@1
   847
         q->ub = +DBL_MAX;
alpar@1
   848
      q->lb = 0.0;
alpar@1
   849
      return;
alpar@1
   850
}
alpar@1
   851
alpar@1
   852
static int rcv_ubnd_col(NPP *npp, void *_info)
alpar@1
   853
{     /* recover column with upper bound */
alpar@1
   854
      struct bnd_col *info = _info;
alpar@1
   855
      if (npp->sol == GLP_BS)
alpar@1
   856
      {  if (npp->c_stat[info->q] == GLP_BS)
alpar@1
   857
            npp->c_stat[info->q] = GLP_BS;
alpar@1
   858
         else if (npp->c_stat[info->q] == GLP_NL)
alpar@1
   859
            npp->c_stat[info->q] = GLP_NU;
alpar@1
   860
         else if (npp->c_stat[info->q] == GLP_NU)
alpar@1
   861
            npp->c_stat[info->q] = GLP_NL;
alpar@1
   862
         else
alpar@1
   863
         {  npp_error();
alpar@1
   864
            return 1;
alpar@1
   865
         }
alpar@1
   866
      }
alpar@1
   867
      /* compute value of x[q] with formula (2) */
alpar@1
   868
      npp->c_value[info->q] = info->bnd - npp->c_value[info->q];
alpar@1
   869
      return 0;
alpar@1
   870
}
alpar@1
   871
alpar@1
   872
/***********************************************************************
alpar@1
   873
*  NAME
alpar@1
   874
*
alpar@1
   875
*  npp_dbnd_col - process non-negative column with upper bound
alpar@1
   876
*
alpar@1
   877
*  SYNOPSIS
alpar@1
   878
*
alpar@1
   879
*  #include "glpnpp.h"
alpar@1
   880
*  void npp_dbnd_col(NPP *npp, NPPCOL *q);
alpar@1
   881
*
alpar@1
   882
*  DESCRIPTION
alpar@1
   883
*
alpar@1
   884
*  The routine npp_dbnd_col processes column q, which is non-negative
alpar@1
   885
*  and has upper bound:
alpar@1
   886
*
alpar@1
   887
*     0 <= x[q] <= u[q],                                             (1)
alpar@1
   888
*
alpar@1
   889
*  where u[q] > 0.
alpar@1
   890
*
alpar@1
   891
*  PROBLEM TRANSFORMATION
alpar@1
   892
*
alpar@1
   893
*  Upper bound of column q can be replaced by the following equality
alpar@1
   894
*  constraint:
alpar@1
   895
*
alpar@1
   896
*     x[q] + s = u[q],                                               (2)
alpar@1
   897
*
alpar@1
   898
*  where s >= 0 is a non-negative complement variable.
alpar@1
   899
*
alpar@1
   900
*  Since in the primal system along with new row (2) there appears a
alpar@1
   901
*  new column s having the only non-zero coefficient in this row, in
alpar@1
   902
*  the dual system there appears a new row:
alpar@1
   903
*
alpar@1
   904
*     (+1)pi + lambda[s] = 0,                                        (3)
alpar@1
   905
*
alpar@1
   906
*  where (+1) is coefficient at column s in row (2), pi is multiplier
alpar@1
   907
*  for row (2), lambda[s] is multiplier for column s, 0 is coefficient
alpar@1
   908
*  at column s in the objective row.
alpar@1
   909
*
alpar@1
   910
*  RECOVERING BASIC SOLUTION
alpar@1
   911
*
alpar@1
   912
*  Status of column q in solution to the original problem is determined
alpar@1
   913
*  by its status and status of column s in solution to the transformed
alpar@1
   914
*  problem as follows:
alpar@1
   915
*
alpar@1
   916
*     +-----------------------------------+------------------+
alpar@1
   917
*     |         Transformed problem       | Original problem |
alpar@1
   918
*     +-----------------+-----------------+------------------+
alpar@1
   919
*     | Status of col q | Status of col s | Status of col q  |
alpar@1
   920
*     +-----------------+-----------------+------------------+
alpar@1
   921
*     |     GLP_BS      |     GLP_BS      |      GLP_BS      |
alpar@1
   922
*     |     GLP_BS      |     GLP_NL      |      GLP_NU      |
alpar@1
   923
*     |     GLP_NL      |     GLP_BS      |      GLP_NL      |
alpar@1
   924
*     |     GLP_NL      |     GLP_NL      |      GLP_NL (*)  |
alpar@1
   925
*     +-----------------+-----------------+------------------+
alpar@1
   926
*
alpar@1
   927
*  Value of column q in solution to the original problem is the same as
alpar@1
   928
*  in solution to the transformed problem.
alpar@1
   929
*
alpar@1
   930
*  1. Formally, in solution to the transformed problem columns q and s
alpar@1
   931
*     cannot be non-basic at the same time, since the constraint (2)
alpar@1
   932
*     would be violated. However, if u[q] is close to zero, violation
alpar@1
   933
*     may be less than a working precision even if both columns q and s
alpar@1
   934
*     are non-basic. In this degenerate case row (2) can be only basic,
alpar@1
   935
*     i.e. non-active constraint (otherwise corresponding row of the
alpar@1
   936
*     basis matrix would be zero). This allows to pivot out auxiliary
alpar@1
   937
*     variable and pivot in column s, in which case the row becomes
alpar@1
   938
*     active while column s becomes basic.
alpar@1
   939
*
alpar@1
   940
*  2. If column q is integral, column s is also integral.
alpar@1
   941
*
alpar@1
   942
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   943
*
alpar@1
   944
*  Value of column q in solution to the original problem is the same as
alpar@1
   945
*  in solution to the transformed problem.
alpar@1
   946
*
alpar@1
   947
*  RECOVERING MIP SOLUTION
alpar@1
   948
*
alpar@1
   949
*  Value of column q in solution to the original problem is the same as
alpar@1
   950
*  in solution to the transformed problem. */
alpar@1
   951
alpar@1
   952
struct dbnd_col
alpar@1
   953
{     /* double-bounded column */
alpar@1
   954
      int q;
alpar@1
   955
      /* column reference number for variable x[q] */
alpar@1
   956
      int s;
alpar@1
   957
      /* column reference number for complement variable s */
alpar@1
   958
};
alpar@1
   959
alpar@1
   960
static int rcv_dbnd_col(NPP *npp, void *info);
alpar@1
   961
alpar@1
   962
void npp_dbnd_col(NPP *npp, NPPCOL *q)
alpar@1
   963
{     /* process non-negative column with upper bound */
alpar@1
   964
      struct dbnd_col *info;
alpar@1
   965
      NPPROW *p;
alpar@1
   966
      NPPCOL *s;
alpar@1
   967
      /* the column must be non-negative with upper bound */
alpar@1
   968
      xassert(q->lb == 0.0);
alpar@1
   969
      xassert(q->ub > 0.0);
alpar@1
   970
      xassert(q->ub != +DBL_MAX);
alpar@1
   971
      /* create variable s */
alpar@1
   972
      s = npp_add_col(npp);
alpar@1
   973
      s->is_int = q->is_int;
alpar@1
   974
      s->lb = 0.0, s->ub = +DBL_MAX;
alpar@1
   975
      /* create equality constraint (2) */
alpar@1
   976
      p = npp_add_row(npp);
alpar@1
   977
      p->lb = p->ub = q->ub;
alpar@1
   978
      npp_add_aij(npp, p, q, +1.0);
alpar@1
   979
      npp_add_aij(npp, p, s, +1.0);
alpar@1
   980
      /* create transformation stack entry */
alpar@1
   981
      info = npp_push_tse(npp,
alpar@1
   982
         rcv_dbnd_col, sizeof(struct dbnd_col));
alpar@1
   983
      info->q = q->j;
alpar@1
   984
      info->s = s->j;
alpar@1
   985
      /* remove upper bound of x[q] */
alpar@1
   986
      q->ub = +DBL_MAX;
alpar@1
   987
      return;
alpar@1
   988
}
alpar@1
   989
alpar@1
   990
static int rcv_dbnd_col(NPP *npp, void *_info)
alpar@1
   991
{     /* recover non-negative column with upper bound */
alpar@1
   992
      struct dbnd_col *info = _info;
alpar@1
   993
      if (npp->sol == GLP_BS)
alpar@1
   994
      {  if (npp->c_stat[info->q] == GLP_BS)
alpar@1
   995
         {  if (npp->c_stat[info->s] == GLP_BS)
alpar@1
   996
               npp->c_stat[info->q] = GLP_BS;
alpar@1
   997
            else if (npp->c_stat[info->s] == GLP_NL)
alpar@1
   998
               npp->c_stat[info->q] = GLP_NU;
alpar@1
   999
            else
alpar@1
  1000
            {  npp_error();
alpar@1
  1001
               return 1;
alpar@1
  1002
            }
alpar@1
  1003
         }
alpar@1
  1004
         else if (npp->c_stat[info->q] == GLP_NL)
alpar@1
  1005
         {  if (npp->c_stat[info->s] == GLP_BS ||
alpar@1
  1006
                npp->c_stat[info->s] == GLP_NL)
alpar@1
  1007
               npp->c_stat[info->q] = GLP_NL;
alpar@1
  1008
            else
alpar@1
  1009
            {  npp_error();
alpar@1
  1010
               return 1;
alpar@1
  1011
            }
alpar@1
  1012
         }
alpar@1
  1013
         else
alpar@1
  1014
         {  npp_error();
alpar@1
  1015
            return 1;
alpar@1
  1016
         }
alpar@1
  1017
      }
alpar@1
  1018
      return 0;
alpar@1
  1019
}
alpar@1
  1020
alpar@1
  1021
/***********************************************************************
alpar@1
  1022
*  NAME
alpar@1
  1023
*
alpar@1
  1024
*  npp_fixed_col - process fixed column
alpar@1
  1025
*
alpar@1
  1026
*  SYNOPSIS
alpar@1
  1027
*
alpar@1
  1028
*  #include "glpnpp.h"
alpar@1
  1029
*  void npp_fixed_col(NPP *npp, NPPCOL *q);
alpar@1
  1030
*
alpar@1
  1031
*  DESCRIPTION
alpar@1
  1032
*
alpar@1
  1033
*  The routine npp_fixed_col processes column q, which is fixed:
alpar@1
  1034
*
alpar@1
  1035
*     x[q] = s[q],                                                   (1)
alpar@1
  1036
*
alpar@1
  1037
*  where s[q] is a fixed column value.
alpar@1
  1038
*
alpar@1
  1039
*  PROBLEM TRANSFORMATION
alpar@1
  1040
*
alpar@1
  1041
*  The value of a fixed column can be substituted into the objective
alpar@1
  1042
*  and constraint rows that allows removing the column from the problem.
alpar@1
  1043
*
alpar@1
  1044
*  Substituting x[q] = s[q] into the objective row, we have:
alpar@1
  1045
*
alpar@1
  1046
*     z = sum c[j] x[j] + c0 =
alpar@1
  1047
*          j
alpar@1
  1048
*
alpar@1
  1049
*       = sum c[j] x[j] + c[q] x[q] + c0 =
alpar@1
  1050
*         j!=q
alpar@1
  1051
*
alpar@1
  1052
*       = sum c[j] x[j] + c[q] s[q] + c0 =
alpar@1
  1053
*         j!=q
alpar@1
  1054
*
alpar@1
  1055
*       = sum c[j] x[j] + c~0,
alpar@1
  1056
*         j!=q
alpar@1
  1057
*
alpar@1
  1058
*  where
alpar@1
  1059
*
alpar@1
  1060
*     c~0 = c0 + c[q] s[q]                                           (2)
alpar@1
  1061
*
alpar@1
  1062
*  is the constant term of the objective in the transformed problem.
alpar@1
  1063
*  Similarly, substituting x[q] = s[q] into constraint row i, we have:
alpar@1
  1064
*
alpar@1
  1065
*     L[i] <= sum a[i,j] x[j] <= U[i]  ==>
alpar@1
  1066
*              j
alpar@1
  1067
*
alpar@1
  1068
*     L[i] <= sum a[i,j] x[j] + a[i,q] x[q] <= U[i]  ==>
alpar@1
  1069
*             j!=q
alpar@1
  1070
*
alpar@1
  1071
*     L[i] <= sum a[i,j] x[j] + a[i,q] s[q] <= U[i]  ==>
alpar@1
  1072
*             j!=q
alpar@1
  1073
*
alpar@1
  1074
*     L~[i] <= sum a[i,j] x[j] + a[i,q] s <= U~[i],
alpar@1
  1075
*              j!=q
alpar@1
  1076
*
alpar@1
  1077
*  where
alpar@1
  1078
*
alpar@1
  1079
*     L~[i] = L[i] - a[i,q] s[q],  U~[i] = U[i] - a[i,q] s[q]        (3)
alpar@1
  1080
*
alpar@1
  1081
*  are lower and upper bounds of row i in the transformed problem,
alpar@1
  1082
*  resp.
alpar@1
  1083
*
alpar@1
  1084
*  RECOVERING BASIC SOLUTION
alpar@1
  1085
*
alpar@1
  1086
*  Column q is assigned status GLP_NS and its value is assigned s[q].
alpar@1
  1087
*
alpar@1
  1088
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  1089
*
alpar@1
  1090
*  Value of column q is assigned s[q].
alpar@1
  1091
*
alpar@1
  1092
*  RECOVERING MIP SOLUTION
alpar@1
  1093
*
alpar@1
  1094
*  Value of column q is assigned s[q]. */
alpar@1
  1095
alpar@1
  1096
struct fixed_col
alpar@1
  1097
{     /* fixed column */
alpar@1
  1098
      int q;
alpar@1
  1099
      /* column reference number for variable x[q] */
alpar@1
  1100
      double s;
alpar@1
  1101
      /* value, at which x[q] is fixed */
alpar@1
  1102
};
alpar@1
  1103
alpar@1
  1104
static int rcv_fixed_col(NPP *npp, void *info);
alpar@1
  1105
alpar@1
  1106
void npp_fixed_col(NPP *npp, NPPCOL *q)
alpar@1
  1107
{     /* process fixed column */
alpar@1
  1108
      struct fixed_col *info;
alpar@1
  1109
      NPPROW *i;
alpar@1
  1110
      NPPAIJ *aij;
alpar@1
  1111
      /* the column must be fixed */
alpar@1
  1112
      xassert(q->lb == q->ub);
alpar@1
  1113
      /* create transformation stack entry */
alpar@1
  1114
      info = npp_push_tse(npp,
alpar@1
  1115
         rcv_fixed_col, sizeof(struct fixed_col));
alpar@1
  1116
      info->q = q->j;
alpar@1
  1117
      info->s = q->lb;
alpar@1
  1118
      /* substitute x[q] = s[q] into objective row */
alpar@1
  1119
      npp->c0 += q->coef * q->lb;
alpar@1
  1120
      /* substitute x[q] = s[q] into constraint rows */
alpar@1
  1121
      for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
  1122
      {  i = aij->row;
alpar@1
  1123
         if (i->lb == i->ub)
alpar@1
  1124
            i->ub = (i->lb -= aij->val * q->lb);
alpar@1
  1125
         else
alpar@1
  1126
         {  if (i->lb != -DBL_MAX)
alpar@1
  1127
               i->lb -= aij->val * q->lb;
alpar@1
  1128
            if (i->ub != +DBL_MAX)
alpar@1
  1129
               i->ub -= aij->val * q->lb;
alpar@1
  1130
         }
alpar@1
  1131
      }
alpar@1
  1132
      /* remove the column from the problem */
alpar@1
  1133
      npp_del_col(npp, q);
alpar@1
  1134
      return;
alpar@1
  1135
}
alpar@1
  1136
alpar@1
  1137
static int rcv_fixed_col(NPP *npp, void *_info)
alpar@1
  1138
{     /* recover fixed column */
alpar@1
  1139
      struct fixed_col *info = _info;
alpar@1
  1140
      if (npp->sol == GLP_SOL)
alpar@1
  1141
         npp->c_stat[info->q] = GLP_NS;
alpar@1
  1142
      npp->c_value[info->q] = info->s;
alpar@1
  1143
      return 0;
alpar@1
  1144
}
alpar@1
  1145
alpar@1
  1146
/***********************************************************************
alpar@1
  1147
*  NAME
alpar@1
  1148
*
alpar@1
  1149
*  npp_make_equality - process row with almost identical bounds
alpar@1
  1150
*
alpar@1
  1151
*  SYNOPSIS
alpar@1
  1152
*
alpar@1
  1153
*  #include "glpnpp.h"
alpar@1
  1154
*  int npp_make_equality(NPP *npp, NPPROW *p);
alpar@1
  1155
*
alpar@1
  1156
*  DESCRIPTION
alpar@1
  1157
*
alpar@1
  1158
*  The routine npp_make_equality processes row p:
alpar@1
  1159
*
alpar@1
  1160
*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
alpar@1
  1161
*              j
alpar@1
  1162
*
alpar@1
  1163
*  where -oo < L[p] < U[p] < +oo, i.e. which is double-sided inequality
alpar@1
  1164
*  constraint.
alpar@1
  1165
*
alpar@1
  1166
*  RETURNS
alpar@1
  1167
*
alpar@1
  1168
*  0 - row bounds have not been changed;
alpar@1
  1169
*
alpar@1
  1170
*  1 - row has been replaced by equality constraint.
alpar@1
  1171
*
alpar@1
  1172
*  PROBLEM TRANSFORMATION
alpar@1
  1173
*
alpar@1
  1174
*  If bounds of row (1) are very close to each other:
alpar@1
  1175
*
alpar@1
  1176
*     U[p] - L[p] <= eps,                                            (2)
alpar@1
  1177
*
alpar@1
  1178
*  where eps is an absolute tolerance for row value, the row can be
alpar@1
  1179
*  replaced by the following almost equivalent equiality constraint:
alpar@1
  1180
*
alpar@1
  1181
*     sum a[p,j] x[j] = b,                                           (3)
alpar@1
  1182
*      j
alpar@1
  1183
*
alpar@1
  1184
*  where b = (L[p] + U[p]) / 2. If the right-hand side in (3) happens
alpar@1
  1185
*  to be very close to its nearest integer:
alpar@1
  1186
*
alpar@1
  1187
*     |b - floor(b + 0.5)| <= eps,                                   (4)
alpar@1
  1188
*
alpar@1
  1189
*  it is reasonable to use this nearest integer as the right-hand side.
alpar@1
  1190
*
alpar@1
  1191
*  RECOVERING BASIC SOLUTION
alpar@1
  1192
*
alpar@1
  1193
*  Status of row p in solution to the original problem is determined
alpar@1
  1194
*  by its status and the sign of its multiplier pi[p] in solution to
alpar@1
  1195
*  the transformed problem as follows:
alpar@1
  1196
*
alpar@1
  1197
*     +-----------------------+---------+--------------------+
alpar@1
  1198
*     |    Status of row p    | Sign of |  Status of row p   |
alpar@1
  1199
*     | (transformed problem) |  pi[p]  | (original problem) |
alpar@1
  1200
*     +-----------------------+---------+--------------------+
alpar@1
  1201
*     |        GLP_BS         |  + / -  |       GLP_BS       |
alpar@1
  1202
*     |        GLP_NS         |    +    |       GLP_NL       |
alpar@1
  1203
*     |        GLP_NS         |    -    |       GLP_NU       |
alpar@1
  1204
*     +-----------------------+---------+--------------------+
alpar@1
  1205
*
alpar@1
  1206
*  Value of row multiplier pi[p] in solution to the original problem is
alpar@1
  1207
*  the same as in solution to the transformed problem.
alpar@1
  1208
*
alpar@1
  1209
*  RECOVERING INTERIOR POINT SOLUTION
alpar@1
  1210
*
alpar@1
  1211
*  Value of row multiplier pi[p] in solution to the original problem is
alpar@1
  1212
*  the same as in solution to the transformed problem.
alpar@1
  1213
*
alpar@1
  1214
*  RECOVERING MIP SOLUTION
alpar@1
  1215
*
alpar@1
  1216
*  None needed. */
alpar@1
  1217
alpar@1
  1218
struct make_equality
alpar@1
  1219
{     /* row with almost identical bounds */
alpar@1
  1220
      int p;
alpar@1
  1221
      /* row reference number */
alpar@1
  1222
};
alpar@1
  1223
alpar@1
  1224
static int rcv_make_equality(NPP *npp, void *info);
alpar@1
  1225
alpar@1
  1226
int npp_make_equality(NPP *npp, NPPROW *p)
alpar@1
  1227
{     /* process row with almost identical bounds */
alpar@1
  1228
      struct make_equality *info;
alpar@1
  1229
      double b, eps, nint;
alpar@1
  1230
      /* the row must be double-sided inequality */
alpar@1
  1231
      xassert(p->lb != -DBL_MAX);
alpar@1
  1232
      xassert(p->ub != +DBL_MAX);
alpar@1
  1233
      xassert(p->lb < p->ub);
alpar@1
  1234
      /* check row bounds */
alpar@1
  1235
      eps = 1e-9 + 1e-12 * fabs(p->lb);
alpar@1
  1236
      if (p->ub - p->lb > eps) return 0;
alpar@1
  1237
      /* row bounds are very close to each other */
alpar@1
  1238
      /* create transformation stack entry */
alpar@1
  1239
      info = npp_push_tse(npp,
alpar@1
  1240
         rcv_make_equality, sizeof(struct make_equality));
alpar@1
  1241
      info->p = p->i;
alpar@1
  1242
      /* compute right-hand side */
alpar@1
  1243
      b = 0.5 * (p->ub + p->lb);
alpar@1
  1244
      nint = floor(b + 0.5);
alpar@1
  1245
      if (fabs(b - nint) <= eps) b = nint;
alpar@1
  1246
      /* replace row p by almost equivalent equality constraint */
alpar@1
  1247
      p->lb = p->ub = b;
alpar@1
  1248
      return 1;
alpar@1
  1249
}
alpar@1
  1250
alpar@1
  1251
int rcv_make_equality(NPP *npp, void *_info)
alpar@1
  1252
{     /* recover row with almost identical bounds */
alpar@1
  1253
      struct make_equality *info = _info;
alpar@1
  1254
      if (npp->sol == GLP_SOL)
alpar@1
  1255
      {  if (npp->r_stat[info->p] == GLP_BS)
alpar@1
  1256
            npp->r_stat[info->p] = GLP_BS;
alpar@1
  1257
         else if (npp->r_stat[info->p] == GLP_NS)
alpar@1
  1258
         {  if (npp->r_pi[info->p] >= 0.0)
alpar@1
  1259
               npp->r_stat[info->p] = GLP_NL;
alpar@1
  1260
            else
alpar@1
  1261
               npp->r_stat[info->p] = GLP_NU;
alpar@1
  1262
         }
alpar@1
  1263
         else
alpar@1
  1264
         {  npp_error();
alpar@1
  1265
            return 1;
alpar@1
  1266
         }
alpar@1
  1267
      }
alpar@1
  1268
      return 0;
alpar@1
  1269
}
alpar@1
  1270
alpar@1
  1271
/***********************************************************************
alpar@1
  1272
*  NAME
alpar@1
  1273
*
alpar@1
  1274
*  npp_make_fixed - process column with almost identical bounds
alpar@1
  1275
*
alpar@1
  1276
*  SYNOPSIS
alpar@1
  1277
*
alpar@1
  1278
*  #include "glpnpp.h"
alpar@1
  1279
*  int npp_make_fixed(NPP *npp, NPPCOL *q);
alpar@1
  1280
*
alpar@1
  1281
*  DESCRIPTION
alpar@1
  1282
*
alpar@1
  1283
*  The routine npp_make_fixed processes column q:
alpar@1
  1284
*
alpar@1
  1285
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
  1286
*
alpar@1
  1287
*  where -oo < l[q] < u[q] < +oo, i.e. which has both lower and upper
alpar@1
  1288
*  bounds.
alpar@1
  1289
*
alpar@1
  1290
*  RETURNS
alpar@1
  1291
*
alpar@1
  1292
*  0 - column bounds have not been changed;
alpar@1
  1293
*
alpar@1
  1294
*  1 - column has been fixed.
alpar@1
  1295
*
alpar@1
  1296
*  PROBLEM TRANSFORMATION
alpar@1
  1297
*
alpar@1
  1298
*  If bounds of column (1) are very close to each other:
alpar@1
  1299
*
alpar@1
  1300
*     u[q] - l[q] <= eps,                                            (2)
alpar@1
  1301
*
alpar@1
  1302
*  where eps is an absolute tolerance for column value, the column can
alpar@1
  1303
*  be fixed:
alpar@1
  1304
*
alpar@1
  1305
*     x[q] = s[q],                                                   (3)
alpar@1
  1306
*
alpar@1
  1307
*  where s[q] = (l[q] + u[q]) / 2. And if the fixed column value s[q]
alpar@1
  1308
*  happens to be very close to its nearest integer:
alpar@1
  1309
*
alpar@1
  1310
*     |s[q] - floor(s[q] + 0.5)| <= eps,                             (4)
alpar@1
  1311
*
alpar@1
  1312
*  it is reasonable to use this nearest integer as the fixed value.
alpar@1
  1313
*
alpar@1
  1314
*  RECOVERING BASIC SOLUTION
alpar@1
  1315
*
alpar@1
  1316
*  In the dual system of the original (as well as transformed) problem
alpar@1
  1317
*  column q corresponds to the following row:
alpar@1
  1318
*
alpar@1
  1319
*     sum a[i,q] pi[i] + lambda[q] = c[q].                           (5)
alpar@1
  1320
*      i
alpar@1
  1321
*
alpar@1
  1322
*  Since multipliers pi[i] are known for all rows from solution to the
alpar@1
  1323
*  transformed problem, formula (5) allows computing value of multiplier
alpar@1
  1324
*  (reduced cost) for column q:
alpar@1
  1325
*
alpar@1
  1326
*     lambda[q] = c[q] - sum a[i,q] pi[i].                           (6)
alpar@1
  1327
*                         i
alpar@1
  1328
*
alpar@1
  1329
*  Status of column q in solution to the original problem is determined
alpar@1
  1330
*  by its status and the sign of its multiplier lambda[q] in solution to
alpar@1
  1331
*  the transformed problem as follows:
alpar@1
  1332
*
alpar@1
  1333
*     +-----------------------+-----------+--------------------+
alpar@1
  1334
*     |  Status of column q   |  Sign of  | Status of column q |
alpar@1
  1335
*     | (transformed problem) | lambda[q] | (original problem) |
alpar@1
  1336
*     +-----------------------+-----------+--------------------+
alpar@1
  1337
*     |        GLP_BS         |   + / -   |       GLP_BS       |
alpar@1
  1338
*     |        GLP_NS         |     +     |       GLP_NL       |
alpar@1
  1339
*     |        GLP_NS         |     -     |       GLP_NU       |
alpar@1
  1340
*     +-----------------------+-----------+--------------------+
alpar@1
  1341
*
alpar@1
  1342
*  Value of column q in solution to the original problem is the same as
alpar@1
  1343
*  in solution to the transformed problem.
alpar@1
  1344
*
alpar@1
  1345
*  RECOVERING INTERIOR POINT SOLUTION
alpar@1
  1346
*
alpar@1
  1347
*  Value of column q in solution to the original problem is the same as
alpar@1
  1348
*  in solution to the transformed problem.
alpar@1
  1349
*
alpar@1
  1350
*  RECOVERING MIP SOLUTION
alpar@1
  1351
*
alpar@1
  1352
*  None needed. */
alpar@1
  1353
alpar@1
  1354
struct make_fixed
alpar@1
  1355
{     /* column with almost identical bounds */
alpar@1
  1356
      int q;
alpar@1
  1357
      /* column reference number */
alpar@1
  1358
      double c;
alpar@1
  1359
      /* objective coefficient at x[q] */
alpar@1
  1360
      NPPLFE *ptr;
alpar@1
  1361
      /* list of non-zero coefficients a[i,q] */
alpar@1
  1362
};
alpar@1
  1363
alpar@1
  1364
static int rcv_make_fixed(NPP *npp, void *info);
alpar@1
  1365
alpar@1
  1366
int npp_make_fixed(NPP *npp, NPPCOL *q)
alpar@1
  1367
{     /* process column with almost identical bounds */
alpar@1
  1368
      struct make_fixed *info;
alpar@1
  1369
      NPPAIJ *aij;
alpar@1
  1370
      NPPLFE *lfe;
alpar@1
  1371
      double s, eps, nint;
alpar@1
  1372
      /* the column must be double-bounded */
alpar@1
  1373
      xassert(q->lb != -DBL_MAX);
alpar@1
  1374
      xassert(q->ub != +DBL_MAX);
alpar@1
  1375
      xassert(q->lb < q->ub);
alpar@1
  1376
      /* check column bounds */
alpar@1
  1377
      eps = 1e-9 + 1e-12 * fabs(q->lb);
alpar@1
  1378
      if (q->ub - q->lb > eps) return 0;
alpar@1
  1379
      /* column bounds are very close to each other */
alpar@1
  1380
      /* create transformation stack entry */
alpar@1
  1381
      info = npp_push_tse(npp,
alpar@1
  1382
         rcv_make_fixed, sizeof(struct make_fixed));
alpar@1
  1383
      info->q = q->j;
alpar@1
  1384
      info->c = q->coef;
alpar@1
  1385
      info->ptr = NULL;
alpar@1
  1386
      /* save column coefficients a[i,q] (needed for basic solution
alpar@1
  1387
         only) */
alpar@1
  1388
      if (npp->sol == GLP_SOL)
alpar@1
  1389
      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
  1390
         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
  1391
            lfe->ref = aij->row->i;
alpar@1
  1392
            lfe->val = aij->val;
alpar@1
  1393
            lfe->next = info->ptr;
alpar@1
  1394
            info->ptr = lfe;
alpar@1
  1395
         }
alpar@1
  1396
      }
alpar@1
  1397
      /* compute column fixed value */
alpar@1
  1398
      s = 0.5 * (q->ub + q->lb);
alpar@1
  1399
      nint = floor(s + 0.5);
alpar@1
  1400
      if (fabs(s - nint) <= eps) s = nint;
alpar@1
  1401
      /* make column q fixed */
alpar@1
  1402
      q->lb = q->ub = s;
alpar@1
  1403
      return 1;
alpar@1
  1404
}
alpar@1
  1405
alpar@1
  1406
static int rcv_make_fixed(NPP *npp, void *_info)
alpar@1
  1407
{     /* recover column with almost identical bounds */
alpar@1
  1408
      struct make_fixed *info = _info;
alpar@1
  1409
      NPPLFE *lfe;
alpar@1
  1410
      double lambda;
alpar@1
  1411
      if (npp->sol == GLP_SOL)
alpar@1
  1412
      {  if (npp->c_stat[info->q] == GLP_BS)
alpar@1
  1413
            npp->c_stat[info->q] = GLP_BS;
alpar@1
  1414
         else if (npp->c_stat[info->q] == GLP_NS)
alpar@1
  1415
         {  /* compute multiplier for column q with formula (6) */
alpar@1
  1416
            lambda = info->c;
alpar@1
  1417
            for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
  1418
               lambda -= lfe->val * npp->r_pi[lfe->ref];
alpar@1
  1419
            /* assign status to non-basic column */
alpar@1
  1420
            if (lambda >= 0.0)
alpar@1
  1421
               npp->c_stat[info->q] = GLP_NL;
alpar@1
  1422
            else
alpar@1
  1423
               npp->c_stat[info->q] = GLP_NU;
alpar@1
  1424
         }
alpar@1
  1425
         else
alpar@1
  1426
         {  npp_error();
alpar@1
  1427
            return 1;
alpar@1
  1428
         }
alpar@1
  1429
      }
alpar@1
  1430
      return 0;
alpar@1
  1431
}
alpar@1
  1432
alpar@1
  1433
/* eof */