src/glpnpp03.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
/* glpnpp03.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_empty_row - process empty row
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  #include "glpnpp.h"
alpar@1
    35
*  int npp_empty_row(NPP *npp, NPPROW *p);
alpar@1
    36
*
alpar@1
    37
*  DESCRIPTION
alpar@1
    38
*
alpar@1
    39
*  The routine npp_empty_row processes row p, which is empty, i.e.
alpar@1
    40
*  coefficients at all columns in this row are zero:
alpar@1
    41
*
alpar@1
    42
*     L[p] <= sum 0 x[j] <= U[p],                                    (1)
alpar@1
    43
*
alpar@1
    44
*  where L[p] <= U[p].
alpar@1
    45
*
alpar@1
    46
*  RETURNS
alpar@1
    47
*
alpar@1
    48
*  0 - success;
alpar@1
    49
*
alpar@1
    50
*  1 - problem has no primal feasible solution.
alpar@1
    51
*
alpar@1
    52
*  PROBLEM TRANSFORMATION
alpar@1
    53
*
alpar@1
    54
*  If the following conditions hold:
alpar@1
    55
*
alpar@1
    56
*     L[p] <= +eps,  U[p] >= -eps,                                   (2)
alpar@1
    57
*
alpar@1
    58
*  where eps is an absolute tolerance for row value, the row p is
alpar@1
    59
*  redundant. In this case it can be replaced by equivalent redundant
alpar@1
    60
*  row, which is free (unbounded), and then removed from the problem.
alpar@1
    61
*  Otherwise, the row p is infeasible and, thus, the problem has no
alpar@1
    62
*  primal feasible solution.
alpar@1
    63
*
alpar@1
    64
*  RECOVERING BASIC SOLUTION
alpar@1
    65
*
alpar@1
    66
*  See the routine npp_free_row.
alpar@1
    67
*
alpar@1
    68
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
    69
*
alpar@1
    70
*  See the routine npp_free_row.
alpar@1
    71
*
alpar@1
    72
*  RECOVERING MIP SOLUTION
alpar@1
    73
*
alpar@1
    74
*  None needed. */
alpar@1
    75
alpar@1
    76
int npp_empty_row(NPP *npp, NPPROW *p)
alpar@1
    77
{     /* process empty row */
alpar@1
    78
      double eps = 1e-3;
alpar@1
    79
      /* the row must be empty */
alpar@1
    80
      xassert(p->ptr == NULL);
alpar@1
    81
      /* check primal feasibility */
alpar@1
    82
      if (p->lb > +eps || p->ub < -eps)
alpar@1
    83
         return 1;
alpar@1
    84
      /* replace the row by equivalent free (unbounded) row */
alpar@1
    85
      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
alpar@1
    86
      /* and process it */
alpar@1
    87
      npp_free_row(npp, p);
alpar@1
    88
      return 0;
alpar@1
    89
}
alpar@1
    90
alpar@1
    91
/***********************************************************************
alpar@1
    92
*  NAME
alpar@1
    93
*
alpar@1
    94
*  npp_empty_col - process empty column
alpar@1
    95
*
alpar@1
    96
*  SYNOPSIS
alpar@1
    97
*
alpar@1
    98
*  #include "glpnpp.h"
alpar@1
    99
*  int npp_empty_col(NPP *npp, NPPCOL *q);
alpar@1
   100
*
alpar@1
   101
*  DESCRIPTION
alpar@1
   102
*
alpar@1
   103
*  The routine npp_empty_col processes column q:
alpar@1
   104
*
alpar@1
   105
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
   106
*
alpar@1
   107
*  where l[q] <= u[q], which is empty, i.e. has zero coefficients in
alpar@1
   108
*  all constraint rows.
alpar@1
   109
*
alpar@1
   110
*  RETURNS
alpar@1
   111
*
alpar@1
   112
*  0 - success;
alpar@1
   113
*
alpar@1
   114
*  1 - problem has no dual feasible solution.
alpar@1
   115
*
alpar@1
   116
*  PROBLEM TRANSFORMATION
alpar@1
   117
*
alpar@1
   118
*  The row of the dual system corresponding to the empty column is the
alpar@1
   119
*  following:
alpar@1
   120
*
alpar@1
   121
*     sum 0 pi[i] + lambda[q] = c[q],                                (2)
alpar@1
   122
*      i
alpar@1
   123
*
alpar@1
   124
*  from which it follows that:
alpar@1
   125
*
alpar@1
   126
*     lambda[q] = c[q].                                              (3)
alpar@1
   127
*
alpar@1
   128
*  If the following condition holds:
alpar@1
   129
*
alpar@1
   130
*     c[q] < - eps,                                                  (4)
alpar@1
   131
*
alpar@1
   132
*  where eps is an absolute tolerance for column multiplier, the lower
alpar@1
   133
*  column bound l[q] must be active to provide dual feasibility (note
alpar@1
   134
*  that being preprocessed the problem is always minimization). In this
alpar@1
   135
*  case the column can be fixed on its lower bound and removed from the
alpar@1
   136
*  problem (if the column is integral, its bounds are also assumed to
alpar@1
   137
*  be integral). And if the column has no lower bound (l[q] = -oo), the
alpar@1
   138
*  problem has no dual feasible solution.
alpar@1
   139
*
alpar@1
   140
*  If the following condition holds:
alpar@1
   141
*
alpar@1
   142
*     c[q] > + eps,                                                  (5)
alpar@1
   143
*
alpar@1
   144
*  the upper column bound u[q] must be active to provide dual
alpar@1
   145
*  feasibility. In this case the column can be fixed on its upper bound
alpar@1
   146
*  and removed from the problem. And if the column has no upper bound
alpar@1
   147
*  (u[q] = +oo), the problem has no dual feasible solution.
alpar@1
   148
*
alpar@1
   149
*  Finally, if the following condition holds:
alpar@1
   150
*
alpar@1
   151
*     - eps <= c[q] <= +eps,                                         (6)
alpar@1
   152
*
alpar@1
   153
*  dual feasibility does not depend on a particular value of column q.
alpar@1
   154
*  In this case the column can be fixed either on its lower bound (if
alpar@1
   155
*  l[q] > -oo) or on its upper bound (if u[q] < +oo) or at zero (if the
alpar@1
   156
*  column is unbounded) and then removed from the problem.
alpar@1
   157
*
alpar@1
   158
*  RECOVERING BASIC SOLUTION
alpar@1
   159
*
alpar@1
   160
*  See the routine npp_fixed_col. Having been recovered the column
alpar@1
   161
*  is assigned status GLP_NS. However, if actually it is not fixed
alpar@1
   162
*  (l[q] < u[q]), its status should be changed to GLP_NL, GLP_NU, or
alpar@1
   163
*  GLP_NF depending on which bound it was fixed on transformation stage.
alpar@1
   164
*
alpar@1
   165
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   166
*
alpar@1
   167
*  See the routine npp_fixed_col.
alpar@1
   168
*
alpar@1
   169
*  RECOVERING MIP SOLUTION
alpar@1
   170
*
alpar@1
   171
*  See the routine npp_fixed_col. */
alpar@1
   172
alpar@1
   173
struct empty_col
alpar@1
   174
{     /* empty column */
alpar@1
   175
      int q;
alpar@1
   176
      /* column reference number */
alpar@1
   177
      char stat;
alpar@1
   178
      /* status in basic solution */
alpar@1
   179
};
alpar@1
   180
alpar@1
   181
static int rcv_empty_col(NPP *npp, void *info);
alpar@1
   182
alpar@1
   183
int npp_empty_col(NPP *npp, NPPCOL *q)
alpar@1
   184
{     /* process empty column */
alpar@1
   185
      struct empty_col *info;
alpar@1
   186
      double eps = 1e-3;
alpar@1
   187
      /* the column must be empty */
alpar@1
   188
      xassert(q->ptr == NULL);
alpar@1
   189
      /* check dual feasibility */
alpar@1
   190
      if (q->coef > +eps && q->lb == -DBL_MAX)
alpar@1
   191
         return 1;
alpar@1
   192
      if (q->coef < -eps && q->ub == +DBL_MAX)
alpar@1
   193
         return 1;
alpar@1
   194
      /* create transformation stack entry */
alpar@1
   195
      info = npp_push_tse(npp,
alpar@1
   196
         rcv_empty_col, sizeof(struct empty_col));
alpar@1
   197
      info->q = q->j;
alpar@1
   198
      /* fix the column */
alpar@1
   199
      if (q->lb == -DBL_MAX && q->ub == +DBL_MAX)
alpar@1
   200
      {  /* free column */
alpar@1
   201
         info->stat = GLP_NF;
alpar@1
   202
         q->lb = q->ub = 0.0;
alpar@1
   203
      }
alpar@1
   204
      else if (q->ub == +DBL_MAX)
alpar@1
   205
lo:   {  /* column with lower bound */
alpar@1
   206
         info->stat = GLP_NL;
alpar@1
   207
         q->ub = q->lb;
alpar@1
   208
      }
alpar@1
   209
      else if (q->lb == -DBL_MAX)
alpar@1
   210
up:   {  /* column with upper bound */
alpar@1
   211
         info->stat = GLP_NU;
alpar@1
   212
         q->lb = q->ub;
alpar@1
   213
      }
alpar@1
   214
      else if (q->lb != q->ub)
alpar@1
   215
      {  /* double-bounded column */
alpar@1
   216
         if (q->coef >= +DBL_EPSILON) goto lo;
alpar@1
   217
         if (q->coef <= -DBL_EPSILON) goto up;
alpar@1
   218
         if (fabs(q->lb) <= fabs(q->ub)) goto lo; else goto up;
alpar@1
   219
      }
alpar@1
   220
      else
alpar@1
   221
      {  /* fixed column */
alpar@1
   222
         info->stat = GLP_NS;
alpar@1
   223
      }
alpar@1
   224
      /* process fixed column */
alpar@1
   225
      npp_fixed_col(npp, q);
alpar@1
   226
      return 0;
alpar@1
   227
}
alpar@1
   228
alpar@1
   229
static int rcv_empty_col(NPP *npp, void *_info)
alpar@1
   230
{     /* recover empty column */
alpar@1
   231
      struct empty_col *info = _info;
alpar@1
   232
      if (npp->sol == GLP_SOL)
alpar@1
   233
         npp->c_stat[info->q] = info->stat;
alpar@1
   234
      return 0;
alpar@1
   235
}
alpar@1
   236
alpar@1
   237
/***********************************************************************
alpar@1
   238
*  NAME
alpar@1
   239
*
alpar@1
   240
*  npp_implied_value - process implied column value
alpar@1
   241
*
alpar@1
   242
*  SYNOPSIS
alpar@1
   243
*
alpar@1
   244
*  #include "glpnpp.h"
alpar@1
   245
*  int npp_implied_value(NPP *npp, NPPCOL *q, double s);
alpar@1
   246
*
alpar@1
   247
*  DESCRIPTION
alpar@1
   248
*
alpar@1
   249
*  For column q:
alpar@1
   250
*
alpar@1
   251
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
   252
*
alpar@1
   253
*  where l[q] < u[q], the routine npp_implied_value processes its
alpar@1
   254
*  implied value s[q]. If this implied value satisfies to the current
alpar@1
   255
*  column bounds and integrality condition, the routine fixes column q
alpar@1
   256
*  at the given point. Note that the column is kept in the problem in
alpar@1
   257
*  any case.
alpar@1
   258
*
alpar@1
   259
*  RETURNS
alpar@1
   260
*
alpar@1
   261
*  0 - column has been fixed;
alpar@1
   262
*
alpar@1
   263
*  1 - implied value violates to current column bounds;
alpar@1
   264
*
alpar@1
   265
*  2 - implied value violates integrality condition.
alpar@1
   266
*
alpar@1
   267
*  ALGORITHM
alpar@1
   268
*
alpar@1
   269
*  Implied column value s[q] satisfies to the current column bounds if
alpar@1
   270
*  the following condition holds:
alpar@1
   271
*
alpar@1
   272
*     l[q] - eps <= s[q] <= u[q] + eps,                              (2)
alpar@1
   273
*
alpar@1
   274
*  where eps is an absolute tolerance for column value. If the column
alpar@1
   275
*  is integral, the following condition also must hold:
alpar@1
   276
*
alpar@1
   277
*     |s[q] - floor(s[q]+0.5)| <= eps,                               (3)
alpar@1
   278
*
alpar@1
   279
*  where floor(s[q]+0.5) is the nearest integer to s[q].
alpar@1
   280
*
alpar@1
   281
*  If both condition (2) and (3) are satisfied, the column can be fixed
alpar@1
   282
*  at the value s[q], or, if it is integral, at floor(s[q]+0.5).
alpar@1
   283
*  Otherwise, if s[q] violates (2) or (3), the problem has no feasible
alpar@1
   284
*  solution.
alpar@1
   285
*
alpar@1
   286
*  Note: If s[q] is close to l[q] or u[q], it seems to be reasonable to
alpar@1
   287
*  fix the column at its lower or upper bound, resp. rather than at the
alpar@1
   288
*  implied value. */
alpar@1
   289
alpar@1
   290
int npp_implied_value(NPP *npp, NPPCOL *q, double s)
alpar@1
   291
{     /* process implied column value */
alpar@1
   292
      double eps, nint;
alpar@1
   293
      xassert(npp == npp);
alpar@1
   294
      /* column must not be fixed */
alpar@1
   295
      xassert(q->lb < q->ub);
alpar@1
   296
      /* check integrality */
alpar@1
   297
      if (q->is_int)
alpar@1
   298
      {  nint = floor(s + 0.5);
alpar@1
   299
         if (fabs(s - nint) <= 1e-5)
alpar@1
   300
            s = nint;
alpar@1
   301
         else
alpar@1
   302
            return 2;
alpar@1
   303
      }
alpar@1
   304
      /* check current column lower bound */
alpar@1
   305
      if (q->lb != -DBL_MAX)
alpar@1
   306
      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
alpar@1
   307
         if (s < q->lb - eps) return 1;
alpar@1
   308
         /* if s[q] is close to l[q], fix column at its lower bound
alpar@1
   309
            rather than at the implied value */
alpar@1
   310
         if (s < q->lb + 1e-3 * eps)
alpar@1
   311
         {  q->ub = q->lb;
alpar@1
   312
            return 0;
alpar@1
   313
         }
alpar@1
   314
      }
alpar@1
   315
      /* check current column upper bound */
alpar@1
   316
      if (q->ub != +DBL_MAX)
alpar@1
   317
      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
alpar@1
   318
         if (s > q->ub + eps) return 1;
alpar@1
   319
         /* if s[q] is close to u[q], fix column at its upper bound
alpar@1
   320
            rather than at the implied value */
alpar@1
   321
         if (s > q->ub - 1e-3 * eps)
alpar@1
   322
         {  q->lb = q->ub;
alpar@1
   323
            return 0;
alpar@1
   324
         }
alpar@1
   325
      }
alpar@1
   326
      /* fix column at the implied value */
alpar@1
   327
      q->lb = q->ub = s;
alpar@1
   328
      return 0;
alpar@1
   329
}
alpar@1
   330
alpar@1
   331
/***********************************************************************
alpar@1
   332
*  NAME
alpar@1
   333
*
alpar@1
   334
*  npp_eq_singlet - process row singleton (equality constraint)
alpar@1
   335
*
alpar@1
   336
*  SYNOPSIS
alpar@1
   337
*
alpar@1
   338
*  #include "glpnpp.h"
alpar@1
   339
*  int npp_eq_singlet(NPP *npp, NPPROW *p);
alpar@1
   340
*
alpar@1
   341
*  DESCRIPTION
alpar@1
   342
*
alpar@1
   343
*  The routine npp_eq_singlet processes row p, which is equiality
alpar@1
   344
*  constraint having the only non-zero coefficient:
alpar@1
   345
*
alpar@1
   346
*     a[p,q] x[q] = b.                                               (1)
alpar@1
   347
*
alpar@1
   348
*  RETURNS
alpar@1
   349
*
alpar@1
   350
*  0 - success;
alpar@1
   351
*
alpar@1
   352
*  1 - problem has no primal feasible solution;
alpar@1
   353
*
alpar@1
   354
*  2 - problem has no integer feasible solution.
alpar@1
   355
*
alpar@1
   356
*  PROBLEM TRANSFORMATION
alpar@1
   357
*
alpar@1
   358
*  The equality constraint defines implied value of column q:
alpar@1
   359
*
alpar@1
   360
*     x[q] = s[q] = b / a[p,q].                                      (2)
alpar@1
   361
*
alpar@1
   362
*  If the implied value s[q] satisfies to the column bounds (see the
alpar@1
   363
*  routine npp_implied_value), the column can be fixed at s[q] and
alpar@1
   364
*  removed from the problem. In this case row p becomes redundant, so
alpar@1
   365
*  it can be replaced by equivalent free row and also removed from the
alpar@1
   366
*  problem.
alpar@1
   367
*
alpar@1
   368
*  Note that the routine removes from the problem only row p. Column q
alpar@1
   369
*  becomes fixed, however, it is kept in the problem.
alpar@1
   370
*
alpar@1
   371
*  RECOVERING BASIC SOLUTION
alpar@1
   372
*
alpar@1
   373
*  In solution to the original problem row p is assigned status GLP_NS
alpar@1
   374
*  (active equality constraint), and column q is assigned status GLP_BS
alpar@1
   375
*  (basic column).
alpar@1
   376
*
alpar@1
   377
*  Multiplier for row p can be computed as follows. In the dual system
alpar@1
   378
*  of the original problem column q corresponds to the following row:
alpar@1
   379
*
alpar@1
   380
*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
alpar@1
   381
*      i
alpar@1
   382
*
alpar@1
   383
*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q].
alpar@1
   384
*     i!=p
alpar@1
   385
*
alpar@1
   386
*  Therefore:
alpar@1
   387
*
alpar@1
   388
*               1
alpar@1
   389
*     pi[p] = ------ (c[q] - lambda[q] - sum a[i,q] pi[i]),          (3)
alpar@1
   390
*             a[p,q]                     i!=q
alpar@1
   391
*
alpar@1
   392
*  where lambda[q] = 0 (since column[q] is basic), and pi[i] for all
alpar@1
   393
*  i != p are known in solution to the transformed problem.
alpar@1
   394
*
alpar@1
   395
*  Value of column q in solution to the original problem is assigned
alpar@1
   396
*  its implied value s[q].
alpar@1
   397
*
alpar@1
   398
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   399
*
alpar@1
   400
*  Multiplier for row p is computed with formula (3). Value of column
alpar@1
   401
*  q is assigned its implied value s[q].
alpar@1
   402
*
alpar@1
   403
*  RECOVERING MIP SOLUTION
alpar@1
   404
*
alpar@1
   405
*  Value of column q is assigned its implied value s[q]. */
alpar@1
   406
alpar@1
   407
struct eq_singlet
alpar@1
   408
{     /* row singleton (equality constraint) */
alpar@1
   409
      int p;
alpar@1
   410
      /* row reference number */
alpar@1
   411
      int q;
alpar@1
   412
      /* column reference number */
alpar@1
   413
      double apq;
alpar@1
   414
      /* constraint coefficient a[p,q] */
alpar@1
   415
      double c;
alpar@1
   416
      /* objective coefficient at x[q] */
alpar@1
   417
      NPPLFE *ptr;
alpar@1
   418
      /* list of non-zero coefficients a[i,q], i != p */
alpar@1
   419
};
alpar@1
   420
alpar@1
   421
static int rcv_eq_singlet(NPP *npp, void *info);
alpar@1
   422
alpar@1
   423
int npp_eq_singlet(NPP *npp, NPPROW *p)
alpar@1
   424
{     /* process row singleton (equality constraint) */
alpar@1
   425
      struct eq_singlet *info;
alpar@1
   426
      NPPCOL *q;
alpar@1
   427
      NPPAIJ *aij;
alpar@1
   428
      NPPLFE *lfe;
alpar@1
   429
      int ret;
alpar@1
   430
      double s;
alpar@1
   431
      /* the row must be singleton equality constraint */
alpar@1
   432
      xassert(p->lb == p->ub);
alpar@1
   433
      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
alpar@1
   434
      /* compute and process implied column value */
alpar@1
   435
      aij = p->ptr;
alpar@1
   436
      q = aij->col;
alpar@1
   437
      s = p->lb / aij->val;
alpar@1
   438
      ret = npp_implied_value(npp, q, s);
alpar@1
   439
      xassert(0 <= ret && ret <= 2);
alpar@1
   440
      if (ret != 0) return ret;
alpar@1
   441
      /* create transformation stack entry */
alpar@1
   442
      info = npp_push_tse(npp,
alpar@1
   443
         rcv_eq_singlet, sizeof(struct eq_singlet));
alpar@1
   444
      info->p = p->i;
alpar@1
   445
      info->q = q->j;
alpar@1
   446
      info->apq = aij->val;
alpar@1
   447
      info->c = q->coef;
alpar@1
   448
      info->ptr = NULL;
alpar@1
   449
      /* save column coefficients a[i,q], i != p (not needed for MIP
alpar@1
   450
         solution) */
alpar@1
   451
      if (npp->sol != GLP_MIP)
alpar@1
   452
      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   453
         {  if (aij->row == p) continue; /* skip a[p,q] */
alpar@1
   454
            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
   455
            lfe->ref = aij->row->i;
alpar@1
   456
            lfe->val = aij->val;
alpar@1
   457
            lfe->next = info->ptr;
alpar@1
   458
            info->ptr = lfe;
alpar@1
   459
         }
alpar@1
   460
      }
alpar@1
   461
      /* remove the row from the problem */
alpar@1
   462
      npp_del_row(npp, p);
alpar@1
   463
      return 0;
alpar@1
   464
}
alpar@1
   465
alpar@1
   466
static int rcv_eq_singlet(NPP *npp, void *_info)
alpar@1
   467
{     /* recover row singleton (equality constraint) */
alpar@1
   468
      struct eq_singlet *info = _info;
alpar@1
   469
      NPPLFE *lfe;
alpar@1
   470
      double temp;
alpar@1
   471
      if (npp->sol == GLP_SOL)
alpar@1
   472
      {  /* column q must be already recovered as GLP_NS */
alpar@1
   473
         if (npp->c_stat[info->q] != GLP_NS)
alpar@1
   474
         {  npp_error();
alpar@1
   475
            return 1;
alpar@1
   476
         }
alpar@1
   477
         npp->r_stat[info->p] = GLP_NS;
alpar@1
   478
         npp->c_stat[info->q] = GLP_BS;
alpar@1
   479
      }
alpar@1
   480
      if (npp->sol != GLP_MIP)
alpar@1
   481
      {  /* compute multiplier for row p with formula (3) */
alpar@1
   482
         temp = info->c;
alpar@1
   483
         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
   484
            temp -= lfe->val * npp->r_pi[lfe->ref];
alpar@1
   485
         npp->r_pi[info->p] = temp / info->apq;
alpar@1
   486
      }
alpar@1
   487
      return 0;
alpar@1
   488
}
alpar@1
   489
alpar@1
   490
/***********************************************************************
alpar@1
   491
*  NAME
alpar@1
   492
*
alpar@1
   493
*  npp_implied_lower - process implied column lower bound
alpar@1
   494
*
alpar@1
   495
*  SYNOPSIS
alpar@1
   496
*
alpar@1
   497
*  #include "glpnpp.h"
alpar@1
   498
*  int npp_implied_lower(NPP *npp, NPPCOL *q, double l);
alpar@1
   499
*
alpar@1
   500
*  DESCRIPTION
alpar@1
   501
*
alpar@1
   502
*  For column q:
alpar@1
   503
*
alpar@1
   504
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
   505
*
alpar@1
   506
*  where l[q] < u[q], the routine npp_implied_lower processes its
alpar@1
   507
*  implied lower bound l'[q]. As the result the current column lower
alpar@1
   508
*  bound may increase. Note that the column is kept in the problem in
alpar@1
   509
*  any case.
alpar@1
   510
*
alpar@1
   511
*  RETURNS
alpar@1
   512
*
alpar@1
   513
*  0 - current column lower bound has not changed;
alpar@1
   514
*
alpar@1
   515
*  1 - current column lower bound has changed, but not significantly;
alpar@1
   516
*
alpar@1
   517
*  2 - current column lower bound has significantly changed;
alpar@1
   518
*
alpar@1
   519
*  3 - column has been fixed on its upper bound;
alpar@1
   520
*
alpar@1
   521
*  4 - implied lower bound violates current column upper bound.
alpar@1
   522
*
alpar@1
   523
*  ALGORITHM
alpar@1
   524
*
alpar@1
   525
*  If column q is integral, before processing its implied lower bound
alpar@1
   526
*  should be rounded up:
alpar@1
   527
*
alpar@1
   528
*              ( floor(l'[q]+0.5), if |l'[q] - floor(l'[q]+0.5)| <= eps
alpar@1
   529
*     l'[q] := <                                                     (2)
alpar@1
   530
*              ( ceil(l'[q]),      otherwise
alpar@1
   531
*
alpar@1
   532
*  where floor(l'[q]+0.5) is the nearest integer to l'[q], ceil(l'[q])
alpar@1
   533
*  is smallest integer not less than l'[q], and eps is an absolute
alpar@1
   534
*  tolerance for column value.
alpar@1
   535
*
alpar@1
   536
*  Processing implied column lower bound l'[q] includes the following
alpar@1
   537
*  cases:
alpar@1
   538
*
alpar@1
   539
*  1) if l'[q] < l[q] + eps, implied lower bound is redundant;
alpar@1
   540
*
alpar@1
   541
*  2) if l[q] + eps <= l[q] <= u[q] + eps, current column lower bound
alpar@1
   542
*     l[q] can be strengthened by replacing it with l'[q]. If in this
alpar@1
   543
*     case new column lower bound becomes close to current column upper
alpar@1
   544
*     bound u[q], the column can be fixed on its upper bound;
alpar@1
   545
*
alpar@1
   546
*  3) if l'[q] > u[q] + eps, implied lower bound violates current
alpar@1
   547
*     column upper bound u[q], in which case the problem has no primal
alpar@1
   548
*     feasible solution. */
alpar@1
   549
alpar@1
   550
int npp_implied_lower(NPP *npp, NPPCOL *q, double l)
alpar@1
   551
{     /* process implied column lower bound */
alpar@1
   552
      int ret;
alpar@1
   553
      double eps, nint;
alpar@1
   554
      xassert(npp == npp);
alpar@1
   555
      /* column must not be fixed */
alpar@1
   556
      xassert(q->lb < q->ub);
alpar@1
   557
      /* implied lower bound must be finite */
alpar@1
   558
      xassert(l != -DBL_MAX);
alpar@1
   559
      /* if column is integral, round up l'[q] */
alpar@1
   560
      if (q->is_int)
alpar@1
   561
      {  nint = floor(l + 0.5);
alpar@1
   562
         if (fabs(l - nint) <= 1e-5)
alpar@1
   563
            l = nint;
alpar@1
   564
         else
alpar@1
   565
            l = ceil(l);
alpar@1
   566
      }
alpar@1
   567
      /* check current column lower bound */
alpar@1
   568
      if (q->lb != -DBL_MAX)
alpar@1
   569
      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->lb));
alpar@1
   570
         if (l < q->lb + eps)
alpar@1
   571
         {  ret = 0; /* redundant */
alpar@1
   572
            goto done;
alpar@1
   573
         }
alpar@1
   574
      }
alpar@1
   575
      /* check current column upper bound */
alpar@1
   576
      if (q->ub != +DBL_MAX)
alpar@1
   577
      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->ub));
alpar@1
   578
         if (l > q->ub + eps)
alpar@1
   579
         {  ret = 4; /* infeasible */
alpar@1
   580
            goto done;
alpar@1
   581
         }
alpar@1
   582
         /* if l'[q] is close to u[q], fix column at its upper bound */
alpar@1
   583
         if (l > q->ub - 1e-3 * eps)
alpar@1
   584
         {  q->lb = q->ub;
alpar@1
   585
            ret = 3; /* fixed */
alpar@1
   586
            goto done;
alpar@1
   587
         }
alpar@1
   588
      }
alpar@1
   589
      /* check if column lower bound changes significantly */
alpar@1
   590
      if (q->lb == -DBL_MAX)
alpar@1
   591
         ret = 2; /* significantly */
alpar@1
   592
      else if (q->is_int && l > q->lb + 0.5)
alpar@1
   593
         ret = 2; /* significantly */
alpar@1
   594
      else if (l > q->lb + 0.30 * (1.0 + fabs(q->lb)))
alpar@1
   595
         ret = 2; /* significantly */
alpar@1
   596
      else
alpar@1
   597
         ret = 1; /* not significantly */
alpar@1
   598
      /* set new column lower bound */
alpar@1
   599
      q->lb = l;
alpar@1
   600
done: return ret;
alpar@1
   601
}
alpar@1
   602
alpar@1
   603
/***********************************************************************
alpar@1
   604
*  NAME
alpar@1
   605
*
alpar@1
   606
*  npp_implied_upper - process implied column upper bound
alpar@1
   607
*
alpar@1
   608
*  SYNOPSIS
alpar@1
   609
*
alpar@1
   610
*  #include "glpnpp.h"
alpar@1
   611
*  int npp_implied_upper(NPP *npp, NPPCOL *q, double u);
alpar@1
   612
*
alpar@1
   613
*  DESCRIPTION
alpar@1
   614
*
alpar@1
   615
*  For column q:
alpar@1
   616
*
alpar@1
   617
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
   618
*
alpar@1
   619
*  where l[q] < u[q], the routine npp_implied_upper processes its
alpar@1
   620
*  implied upper bound u'[q]. As the result the current column upper
alpar@1
   621
*  bound may decrease. Note that the column is kept in the problem in
alpar@1
   622
*  any case.
alpar@1
   623
*
alpar@1
   624
*  RETURNS
alpar@1
   625
*
alpar@1
   626
*  0 - current column upper bound has not changed;
alpar@1
   627
*
alpar@1
   628
*  1 - current column upper bound has changed, but not significantly;
alpar@1
   629
*
alpar@1
   630
*  2 - current column upper bound has significantly changed;
alpar@1
   631
*
alpar@1
   632
*  3 - column has been fixed on its lower bound;
alpar@1
   633
*
alpar@1
   634
*  4 - implied upper bound violates current column lower bound.
alpar@1
   635
*
alpar@1
   636
*  ALGORITHM
alpar@1
   637
*
alpar@1
   638
*  If column q is integral, before processing its implied upper bound
alpar@1
   639
*  should be rounded down:
alpar@1
   640
*
alpar@1
   641
*              ( floor(u'[q]+0.5), if |u'[q] - floor(l'[q]+0.5)| <= eps
alpar@1
   642
*     u'[q] := <                                                     (2)
alpar@1
   643
*              ( floor(l'[q]),     otherwise
alpar@1
   644
*
alpar@1
   645
*  where floor(u'[q]+0.5) is the nearest integer to u'[q],
alpar@1
   646
*  floor(u'[q]) is largest integer not greater than u'[q], and eps is
alpar@1
   647
*  an absolute tolerance for column value.
alpar@1
   648
*
alpar@1
   649
*  Processing implied column upper bound u'[q] includes the following
alpar@1
   650
*  cases:
alpar@1
   651
*
alpar@1
   652
*  1) if u'[q] > u[q] - eps, implied upper bound is redundant;
alpar@1
   653
*
alpar@1
   654
*  2) if l[q] - eps <= u[q] <= u[q] - eps, current column upper bound
alpar@1
   655
*     u[q] can be strengthened by replacing it with u'[q]. If in this
alpar@1
   656
*     case new column upper bound becomes close to current column lower
alpar@1
   657
*     bound, the column can be fixed on its lower bound;
alpar@1
   658
*
alpar@1
   659
*  3) if u'[q] < l[q] - eps, implied upper bound violates current
alpar@1
   660
*     column lower bound l[q], in which case the problem has no primal
alpar@1
   661
*     feasible solution. */
alpar@1
   662
alpar@1
   663
int npp_implied_upper(NPP *npp, NPPCOL *q, double u)
alpar@1
   664
{     int ret;
alpar@1
   665
      double eps, nint;
alpar@1
   666
      xassert(npp == npp);
alpar@1
   667
      /* column must not be fixed */
alpar@1
   668
      xassert(q->lb < q->ub);
alpar@1
   669
      /* implied upper bound must be finite */
alpar@1
   670
      xassert(u != +DBL_MAX);
alpar@1
   671
      /* if column is integral, round down u'[q] */
alpar@1
   672
      if (q->is_int)
alpar@1
   673
      {  nint = floor(u + 0.5);
alpar@1
   674
         if (fabs(u - nint) <= 1e-5)
alpar@1
   675
            u = nint;
alpar@1
   676
         else
alpar@1
   677
            u = floor(u);
alpar@1
   678
      }
alpar@1
   679
      /* check current column upper bound */
alpar@1
   680
      if (q->ub != +DBL_MAX)
alpar@1
   681
      {  eps = (q->is_int ? 1e-3 : 1e-3 + 1e-6 * fabs(q->ub));
alpar@1
   682
         if (u > q->ub - eps)
alpar@1
   683
         {  ret = 0; /* redundant */
alpar@1
   684
            goto done;
alpar@1
   685
         }
alpar@1
   686
      }
alpar@1
   687
      /* check current column lower bound */
alpar@1
   688
      if (q->lb != -DBL_MAX)
alpar@1
   689
      {  eps = (q->is_int ? 1e-5 : 1e-5 + 1e-8 * fabs(q->lb));
alpar@1
   690
         if (u < q->lb - eps)
alpar@1
   691
         {  ret = 4; /* infeasible */
alpar@1
   692
            goto done;
alpar@1
   693
         }
alpar@1
   694
         /* if u'[q] is close to l[q], fix column at its lower bound */
alpar@1
   695
         if (u < q->lb + 1e-3 * eps)
alpar@1
   696
         {  q->ub = q->lb;
alpar@1
   697
            ret = 3; /* fixed */
alpar@1
   698
            goto done;
alpar@1
   699
         }
alpar@1
   700
      }
alpar@1
   701
      /* check if column upper bound changes significantly */
alpar@1
   702
      if (q->ub == +DBL_MAX)
alpar@1
   703
         ret = 2; /* significantly */
alpar@1
   704
      else if (q->is_int && u < q->ub - 0.5)
alpar@1
   705
         ret = 2; /* significantly */
alpar@1
   706
      else if (u < q->ub - 0.30 * (1.0 + fabs(q->ub)))
alpar@1
   707
         ret = 2; /* significantly */
alpar@1
   708
      else
alpar@1
   709
         ret = 1; /* not significantly */
alpar@1
   710
      /* set new column upper bound */
alpar@1
   711
      q->ub = u;
alpar@1
   712
done: return ret;
alpar@1
   713
}
alpar@1
   714
alpar@1
   715
/***********************************************************************
alpar@1
   716
*  NAME
alpar@1
   717
*
alpar@1
   718
*  npp_ineq_singlet - process row singleton (inequality constraint)
alpar@1
   719
*
alpar@1
   720
*  SYNOPSIS
alpar@1
   721
*
alpar@1
   722
*  #include "glpnpp.h"
alpar@1
   723
*  int npp_ineq_singlet(NPP *npp, NPPROW *p);
alpar@1
   724
*
alpar@1
   725
*  DESCRIPTION
alpar@1
   726
*
alpar@1
   727
*  The routine npp_ineq_singlet processes row p, which is inequality
alpar@1
   728
*  constraint having the only non-zero coefficient:
alpar@1
   729
*
alpar@1
   730
*     L[p] <= a[p,q] * x[q] <= U[p],                                 (1)
alpar@1
   731
*
alpar@1
   732
*  where L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
alpar@1
   733
*
alpar@1
   734
*  RETURNS
alpar@1
   735
*
alpar@1
   736
*  0 - current column bounds have not changed;
alpar@1
   737
*
alpar@1
   738
*  1 - current column bounds have changed, but not significantly;
alpar@1
   739
*
alpar@1
   740
*  2 - current column bounds have significantly changed;
alpar@1
   741
*
alpar@1
   742
*  3 - column has been fixed on its lower or upper bound;
alpar@1
   743
*
alpar@1
   744
*  4 - problem has no primal feasible solution.
alpar@1
   745
*
alpar@1
   746
*  PROBLEM TRANSFORMATION
alpar@1
   747
*
alpar@1
   748
*  Inequality constraint (1) defines implied bounds of column q:
alpar@1
   749
*
alpar@1
   750
*             (  L[p] / a[p,q],  if a[p,q] > 0
alpar@1
   751
*     l'[q] = <                                                      (2)
alpar@1
   752
*             (  U[p] / a[p,q],  if a[p,q] < 0
alpar@1
   753
*
alpar@1
   754
*             (  U[p] / a[p,q],  if a[p,q] > 0
alpar@1
   755
*     u'[q] = <                                                      (3)
alpar@1
   756
*             (  L[p] / a[p,q],  if a[p,q] < 0
alpar@1
   757
*
alpar@1
   758
*  If these implied bounds do not violate current bounds of column q:
alpar@1
   759
*
alpar@1
   760
*     l[q] <= x[q] <= u[q],                                          (4)
alpar@1
   761
*
alpar@1
   762
*  they can be used to strengthen the current column bounds:
alpar@1
   763
*
alpar@1
   764
*     l[q] := max(l[q], l'[q]),                                      (5)
alpar@1
   765
*
alpar@1
   766
*     u[q] := min(u[q], u'[q]).                                      (6)
alpar@1
   767
*
alpar@1
   768
*  (See the routines npp_implied_lower and npp_implied_upper.)
alpar@1
   769
*
alpar@1
   770
*  Once bounds of row p (1) have been carried over column q, the row
alpar@1
   771
*  becomes redundant, so it can be replaced by equivalent free row and
alpar@1
   772
*  removed from the problem.
alpar@1
   773
*
alpar@1
   774
*  Note that the routine removes from the problem only row p. Column q,
alpar@1
   775
*  even it has been fixed, is kept in the problem.
alpar@1
   776
*
alpar@1
   777
*  RECOVERING BASIC SOLUTION
alpar@1
   778
*
alpar@1
   779
*  Note that the row in the dual system corresponding to column q is
alpar@1
   780
*  the following:
alpar@1
   781
*
alpar@1
   782
*     sum a[i,q] pi[i] + lambda[q] = c[q]  ==>
alpar@1
   783
*      i
alpar@1
   784
*                                                                    (7)
alpar@1
   785
*     sum a[i,q] pi[i] + a[p,q] pi[p] + lambda[q] = c[q],
alpar@1
   786
*     i!=p
alpar@1
   787
*
alpar@1
   788
*  where pi[i] for all i != p are known in solution to the transformed
alpar@1
   789
*  problem. Row p does not exist in the transformed problem, so it has
alpar@1
   790
*  zero multiplier there. This allows computing multiplier for column q
alpar@1
   791
*  in solution to the transformed problem:
alpar@1
   792
*
alpar@1
   793
*     lambda~[q] = c[q] - sum a[i,q] pi[i].                          (8)
alpar@1
   794
*                         i!=p
alpar@1
   795
*
alpar@1
   796
*  Let in solution to the transformed problem column q be non-basic
alpar@1
   797
*  with lower bound active (GLP_NL, lambda~[q] >= 0), and this lower
alpar@1
   798
*  bound be implied one l'[q]. From the original problem's standpoint
alpar@1
   799
*  this then means that actually the original column lower bound l[q]
alpar@1
   800
*  is inactive, and active is that row bound L[p] or U[p] that defines
alpar@1
   801
*  the implied bound l'[q] (2). In this case in solution to the
alpar@1
   802
*  original problem column q is assigned status GLP_BS while row p is
alpar@1
   803
*  assigned status GLP_NL (if a[p,q] > 0) or GLP_NU (if a[p,q] < 0).
alpar@1
   804
*  Since now column q is basic, its multiplier lambda[q] is zero. This
alpar@1
   805
*  allows using (7) and (8) to find multiplier for row p in solution to
alpar@1
   806
*  the original problem:
alpar@1
   807
*
alpar@1
   808
*               1
alpar@1
   809
*     pi[p] = ------ (c[q] - sum a[i,q] pi[i]) = lambda~[q] / a[p,q] (9)
alpar@1
   810
*             a[p,q]         i!=p
alpar@1
   811
*
alpar@1
   812
*  Now let in solution to the transformed problem column q be non-basic
alpar@1
   813
*  with upper bound active (GLP_NU, lambda~[q] <= 0), and this upper
alpar@1
   814
*  bound be implied one u'[q]. As in the previous case this then means
alpar@1
   815
*  that from the original problem's standpoint actually the original
alpar@1
   816
*  column upper bound u[q] is inactive, and active is that row bound
alpar@1
   817
*  L[p] or U[p] that defines the implied bound u'[q] (3). In this case
alpar@1
   818
*  in solution to the original problem column q is assigned status
alpar@1
   819
*  GLP_BS, row p is assigned status GLP_NU (if a[p,q] > 0) or GLP_NL
alpar@1
   820
*  (if a[p,q] < 0), and its multiplier is computed with formula (9).
alpar@1
   821
*
alpar@1
   822
*  Strengthening bounds of column q according to (5) and (6) may make
alpar@1
   823
*  it fixed. Thus, if in solution to the transformed problem column q is
alpar@1
   824
*  non-basic and fixed (GLP_NS), we can suppose that if lambda~[q] > 0,
alpar@1
   825
*  column q has active lower bound (GLP_NL), and if lambda~[q] < 0,
alpar@1
   826
*  column q has active upper bound (GLP_NU), reducing this case to two
alpar@1
   827
*  previous ones. If, however, lambda~[q] is close to zero or
alpar@1
   828
*  corresponding bound of row p does not exist (this may happen if
alpar@1
   829
*  lambda~[q] has wrong sign due to round-off errors, in which case it
alpar@1
   830
*  is expected to be close to zero, since solution is assumed to be dual
alpar@1
   831
*  feasible), column q can be assigned status GLP_BS (basic), and row p
alpar@1
   832
*  can be made active on its existing bound. In the latter case row
alpar@1
   833
*  multiplier pi[p] computed with formula (9) will be also close to
alpar@1
   834
*  zero, and dual feasibility will be kept.
alpar@1
   835
*
alpar@1
   836
*  In all other cases, namely, if in solution to the transformed
alpar@1
   837
*  problem column q is basic (GLP_BS), or non-basic with original lower
alpar@1
   838
*  bound l[q] active (GLP_NL), or non-basic with original upper bound
alpar@1
   839
*  u[q] active (GLP_NU), constraint (1) is inactive. So in solution to
alpar@1
   840
*  the original problem status of column q remains unchanged, row p is
alpar@1
   841
*  assigned status GLP_BS, and its multiplier pi[p] is assigned zero
alpar@1
   842
*  value.
alpar@1
   843
*
alpar@1
   844
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
   845
*
alpar@1
   846
*  First, value of multiplier for column q in solution to the original
alpar@1
   847
*  problem is computed with formula (8). If lambda~[q] > 0 and column q
alpar@1
   848
*  has implied lower bound, or if lambda~[q] < 0 and column q has
alpar@1
   849
*  implied upper bound, this means that from the original problem's
alpar@1
   850
*  standpoint actually row p has corresponding active bound, in which
alpar@1
   851
*  case its multiplier pi[p] is computed with formula (9). In other
alpar@1
   852
*  cases, when the sign of lambda~[q] corresponds to original bound of
alpar@1
   853
*  column q, or when lambda~[q] =~ 0, value of row multiplier pi[p] is
alpar@1
   854
*  assigned zero value.
alpar@1
   855
*
alpar@1
   856
*  RECOVERING MIP SOLUTION
alpar@1
   857
*
alpar@1
   858
*  None needed. */
alpar@1
   859
alpar@1
   860
struct ineq_singlet
alpar@1
   861
{     /* row singleton (inequality constraint) */
alpar@1
   862
      int p;
alpar@1
   863
      /* row reference number */
alpar@1
   864
      int q;
alpar@1
   865
      /* column reference number */
alpar@1
   866
      double apq;
alpar@1
   867
      /* constraint coefficient a[p,q] */
alpar@1
   868
      double c;
alpar@1
   869
      /* objective coefficient at x[q] */
alpar@1
   870
      double lb;
alpar@1
   871
      /* row lower bound */
alpar@1
   872
      double ub;
alpar@1
   873
      /* row upper bound */
alpar@1
   874
      char lb_changed;
alpar@1
   875
      /* this flag is set if column lower bound was changed */
alpar@1
   876
      char ub_changed;
alpar@1
   877
      /* this flag is set if column upper bound was changed */
alpar@1
   878
      NPPLFE *ptr;
alpar@1
   879
      /* list of non-zero coefficients a[i,q], i != p */
alpar@1
   880
};
alpar@1
   881
alpar@1
   882
static int rcv_ineq_singlet(NPP *npp, void *info);
alpar@1
   883
alpar@1
   884
int npp_ineq_singlet(NPP *npp, NPPROW *p)
alpar@1
   885
{     /* process row singleton (inequality constraint) */
alpar@1
   886
      struct ineq_singlet *info;
alpar@1
   887
      NPPCOL *q;
alpar@1
   888
      NPPAIJ *apq, *aij;
alpar@1
   889
      NPPLFE *lfe;
alpar@1
   890
      int lb_changed, ub_changed;
alpar@1
   891
      double ll, uu;
alpar@1
   892
      /* the row must be singleton inequality constraint */
alpar@1
   893
      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
alpar@1
   894
      xassert(p->lb < p->ub);
alpar@1
   895
      xassert(p->ptr != NULL && p->ptr->r_next == NULL);
alpar@1
   896
      /* compute implied column bounds */
alpar@1
   897
      apq = p->ptr;
alpar@1
   898
      q = apq->col;
alpar@1
   899
      xassert(q->lb < q->ub);
alpar@1
   900
      if (apq->val > 0.0)
alpar@1
   901
      {  ll = (p->lb == -DBL_MAX ? -DBL_MAX : p->lb / apq->val);
alpar@1
   902
         uu = (p->ub == +DBL_MAX ? +DBL_MAX : p->ub / apq->val);
alpar@1
   903
      }
alpar@1
   904
      else
alpar@1
   905
      {  ll = (p->ub == +DBL_MAX ? -DBL_MAX : p->ub / apq->val);
alpar@1
   906
         uu = (p->lb == -DBL_MAX ? +DBL_MAX : p->lb / apq->val);
alpar@1
   907
      }
alpar@1
   908
      /* process implied column lower bound */
alpar@1
   909
      if (ll == -DBL_MAX)
alpar@1
   910
         lb_changed = 0;
alpar@1
   911
      else
alpar@1
   912
      {  lb_changed = npp_implied_lower(npp, q, ll);
alpar@1
   913
         xassert(0 <= lb_changed && lb_changed <= 4);
alpar@1
   914
         if (lb_changed == 4) return 4; /* infeasible */
alpar@1
   915
      }
alpar@1
   916
      /* process implied column upper bound */
alpar@1
   917
      if (uu == +DBL_MAX)
alpar@1
   918
         ub_changed = 0;
alpar@1
   919
      else if (lb_changed == 3)
alpar@1
   920
      {  /* column was fixed on its upper bound due to l'[q] = u[q] */
alpar@1
   921
         /* note that L[p] < U[p], so l'[q] = u[q] < u'[q] */
alpar@1
   922
         ub_changed = 0;
alpar@1
   923
      }
alpar@1
   924
      else
alpar@1
   925
      {  ub_changed = npp_implied_upper(npp, q, uu);
alpar@1
   926
         xassert(0 <= ub_changed && ub_changed <= 4);
alpar@1
   927
         if (ub_changed == 4) return 4; /* infeasible */
alpar@1
   928
      }
alpar@1
   929
      /* if neither lower nor upper column bound was changed, the row
alpar@1
   930
         is originally redundant and can be replaced by free row */
alpar@1
   931
      if (!lb_changed && !ub_changed)
alpar@1
   932
      {  p->lb = -DBL_MAX, p->ub = +DBL_MAX;
alpar@1
   933
         npp_free_row(npp, p);
alpar@1
   934
         return 0;
alpar@1
   935
      }
alpar@1
   936
      /* create transformation stack entry */
alpar@1
   937
      info = npp_push_tse(npp,
alpar@1
   938
         rcv_ineq_singlet, sizeof(struct ineq_singlet));
alpar@1
   939
      info->p = p->i;
alpar@1
   940
      info->q = q->j;
alpar@1
   941
      info->apq = apq->val;
alpar@1
   942
      info->c = q->coef;
alpar@1
   943
      info->lb = p->lb;
alpar@1
   944
      info->ub = p->ub;
alpar@1
   945
      info->lb_changed = (char)lb_changed;
alpar@1
   946
      info->ub_changed = (char)ub_changed;
alpar@1
   947
      info->ptr = NULL;
alpar@1
   948
      /* save column coefficients a[i,q], i != p (not needed for MIP
alpar@1
   949
         solution) */
alpar@1
   950
      if (npp->sol != GLP_MIP)
alpar@1
   951
      {  for (aij = q->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   952
         {  if (aij == apq) continue; /* skip a[p,q] */
alpar@1
   953
            lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
   954
            lfe->ref = aij->row->i;
alpar@1
   955
            lfe->val = aij->val;
alpar@1
   956
            lfe->next = info->ptr;
alpar@1
   957
            info->ptr = lfe;
alpar@1
   958
         }
alpar@1
   959
      }
alpar@1
   960
      /* remove the row from the problem */
alpar@1
   961
      npp_del_row(npp, p);
alpar@1
   962
      return lb_changed >= ub_changed ? lb_changed : ub_changed;
alpar@1
   963
}
alpar@1
   964
alpar@1
   965
static int rcv_ineq_singlet(NPP *npp, void *_info)
alpar@1
   966
{     /* recover row singleton (inequality constraint) */
alpar@1
   967
      struct ineq_singlet *info = _info;
alpar@1
   968
      NPPLFE *lfe;
alpar@1
   969
      double lambda;
alpar@1
   970
      if (npp->sol == GLP_MIP) goto done;
alpar@1
   971
      /* compute lambda~[q] in solution to the transformed problem
alpar@1
   972
         with formula (8) */
alpar@1
   973
      lambda = info->c;
alpar@1
   974
      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
   975
         lambda -= lfe->val * npp->r_pi[lfe->ref];
alpar@1
   976
      if (npp->sol == GLP_SOL)
alpar@1
   977
      {  /* recover basic solution */
alpar@1
   978
         if (npp->c_stat[info->q] == GLP_BS)
alpar@1
   979
         {  /* column q is basic, so row p is inactive */
alpar@1
   980
            npp->r_stat[info->p] = GLP_BS;
alpar@1
   981
            npp->r_pi[info->p] = 0.0;
alpar@1
   982
         }
alpar@1
   983
         else if (npp->c_stat[info->q] == GLP_NL)
alpar@1
   984
nl:      {  /* column q is non-basic with lower bound active */
alpar@1
   985
            if (info->lb_changed)
alpar@1
   986
            {  /* it is implied bound, so actually row p is active
alpar@1
   987
                  while column q is basic */
alpar@1
   988
               npp->r_stat[info->p] =
alpar@1
   989
                  (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
alpar@1
   990
               npp->c_stat[info->q] = GLP_BS;
alpar@1
   991
               npp->r_pi[info->p] = lambda / info->apq;
alpar@1
   992
            }
alpar@1
   993
            else
alpar@1
   994
            {  /* it is original bound, so row p is inactive */
alpar@1
   995
               npp->r_stat[info->p] = GLP_BS;
alpar@1
   996
               npp->r_pi[info->p] = 0.0;
alpar@1
   997
            }
alpar@1
   998
         }
alpar@1
   999
         else if (npp->c_stat[info->q] == GLP_NU)
alpar@1
  1000
nu:      {  /* column q is non-basic with upper bound active */
alpar@1
  1001
            if (info->ub_changed)
alpar@1
  1002
            {  /* it is implied bound, so actually row p is active
alpar@1
  1003
                  while column q is basic */
alpar@1
  1004
               npp->r_stat[info->p] =
alpar@1
  1005
                  (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
alpar@1
  1006
               npp->c_stat[info->q] = GLP_BS;
alpar@1
  1007
               npp->r_pi[info->p] = lambda / info->apq;
alpar@1
  1008
            }
alpar@1
  1009
            else
alpar@1
  1010
            {  /* it is original bound, so row p is inactive */
alpar@1
  1011
               npp->r_stat[info->p] = GLP_BS;
alpar@1
  1012
               npp->r_pi[info->p] = 0.0;
alpar@1
  1013
            }
alpar@1
  1014
         }
alpar@1
  1015
         else if (npp->c_stat[info->q] == GLP_NS)
alpar@1
  1016
         {  /* column q is non-basic and fixed; note, however, that in
alpar@1
  1017
               in the original problem it is non-fixed */
alpar@1
  1018
            if (lambda > +1e-7)
alpar@1
  1019
            {  if (info->apq > 0.0 && info->lb != -DBL_MAX ||
alpar@1
  1020
                   info->apq < 0.0 && info->ub != +DBL_MAX ||
alpar@1
  1021
                  !info->lb_changed)
alpar@1
  1022
               {  /* either corresponding bound of row p exists or
alpar@1
  1023
                     column q remains non-basic with its original lower
alpar@1
  1024
                     bound active */
alpar@1
  1025
                  npp->c_stat[info->q] = GLP_NL;
alpar@1
  1026
                  goto nl;
alpar@1
  1027
               }
alpar@1
  1028
            }
alpar@1
  1029
            if (lambda < -1e-7)
alpar@1
  1030
            {  if (info->apq > 0.0 && info->ub != +DBL_MAX ||
alpar@1
  1031
                   info->apq < 0.0 && info->lb != -DBL_MAX ||
alpar@1
  1032
                  !info->ub_changed)
alpar@1
  1033
               {  /* either corresponding bound of row p exists or
alpar@1
  1034
                     column q remains non-basic with its original upper
alpar@1
  1035
                     bound active */
alpar@1
  1036
                  npp->c_stat[info->q] = GLP_NU;
alpar@1
  1037
                  goto nu;
alpar@1
  1038
               }
alpar@1
  1039
            }
alpar@1
  1040
            /* either lambda~[q] is close to zero, or corresponding
alpar@1
  1041
               bound of row p does not exist, because lambda~[q] has
alpar@1
  1042
               wrong sign due to round-off errors; in the latter case
alpar@1
  1043
               lambda~[q] is also assumed to be close to zero; so, we
alpar@1
  1044
               can make row p active on its existing bound and column q
alpar@1
  1045
               basic; pi[p] will have wrong sign, but it also will be
alpar@1
  1046
               close to zero (rarus casus of dual degeneracy) */
alpar@1
  1047
            if (info->lb != -DBL_MAX && info->ub == +DBL_MAX)
alpar@1
  1048
            {  /* row lower bound exists, but upper bound doesn't */
alpar@1
  1049
               npp->r_stat[info->p] = GLP_NL;
alpar@1
  1050
            }
alpar@1
  1051
            else if (info->lb == -DBL_MAX && info->ub != +DBL_MAX)
alpar@1
  1052
            {  /* row upper bound exists, but lower bound doesn't */
alpar@1
  1053
               npp->r_stat[info->p] = GLP_NU;
alpar@1
  1054
            }
alpar@1
  1055
            else if (info->lb != -DBL_MAX && info->ub != +DBL_MAX)
alpar@1
  1056
            {  /* both row lower and upper bounds exist */
alpar@1
  1057
               /* to choose proper active row bound we should not use
alpar@1
  1058
                  lambda~[q], because its value being close to zero is
alpar@1
  1059
                  unreliable; so we choose that bound which provides
alpar@1
  1060
                  primal feasibility for original constraint (1) */
alpar@1
  1061
               if (info->apq * npp->c_value[info->q] <=
alpar@1
  1062
                   0.5 * (info->lb + info->ub))
alpar@1
  1063
                  npp->r_stat[info->p] = GLP_NL;
alpar@1
  1064
               else
alpar@1
  1065
                  npp->r_stat[info->p] = GLP_NU;
alpar@1
  1066
            }
alpar@1
  1067
            else
alpar@1
  1068
            {  npp_error();
alpar@1
  1069
               return 1;
alpar@1
  1070
            }
alpar@1
  1071
            npp->c_stat[info->q] = GLP_BS;
alpar@1
  1072
            npp->r_pi[info->p] = lambda / info->apq;
alpar@1
  1073
         }
alpar@1
  1074
         else
alpar@1
  1075
         {  npp_error();
alpar@1
  1076
            return 1;
alpar@1
  1077
         }
alpar@1
  1078
      }
alpar@1
  1079
      if (npp->sol == GLP_IPT)
alpar@1
  1080
      {  /* recover interior-point solution */
alpar@1
  1081
         if (lambda > +DBL_EPSILON && info->lb_changed ||
alpar@1
  1082
             lambda < -DBL_EPSILON && info->ub_changed)
alpar@1
  1083
         {  /* actually row p has corresponding active bound */
alpar@1
  1084
            npp->r_pi[info->p] = lambda / info->apq;
alpar@1
  1085
         }
alpar@1
  1086
         else
alpar@1
  1087
         {  /* either bounds of column q are both inactive or its
alpar@1
  1088
               original bound is active */
alpar@1
  1089
            npp->r_pi[info->p] = 0.0;
alpar@1
  1090
         }
alpar@1
  1091
      }
alpar@1
  1092
done: return 0;
alpar@1
  1093
}
alpar@1
  1094
alpar@1
  1095
/***********************************************************************
alpar@1
  1096
*  NAME
alpar@1
  1097
*
alpar@1
  1098
*  npp_implied_slack - process column singleton (implied slack variable)
alpar@1
  1099
*
alpar@1
  1100
*  SYNOPSIS
alpar@1
  1101
*
alpar@1
  1102
*  #include "glpnpp.h"
alpar@1
  1103
*  void npp_implied_slack(NPP *npp, NPPCOL *q);
alpar@1
  1104
*
alpar@1
  1105
*  DESCRIPTION
alpar@1
  1106
*
alpar@1
  1107
*  The routine npp_implied_slack processes column q:
alpar@1
  1108
*
alpar@1
  1109
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
  1110
*
alpar@1
  1111
*  where l[q] < u[q], having the only non-zero coefficient in row p,
alpar@1
  1112
*  which is equality constraint:
alpar@1
  1113
*
alpar@1
  1114
*     sum a[p,j] x[j] + a[p,q] x[q] = b.                             (2)
alpar@1
  1115
*     j!=q
alpar@1
  1116
*
alpar@1
  1117
*  PROBLEM TRANSFORMATION
alpar@1
  1118
*
alpar@1
  1119
*  (If x[q] is integral, this transformation must not be used.)
alpar@1
  1120
*
alpar@1
  1121
*  The term a[p,q] x[q] in constraint (2) can be considered as a slack
alpar@1
  1122
*  variable that allows to carry bounds of column q over row p and then
alpar@1
  1123
*  remove column q from the problem.
alpar@1
  1124
*
alpar@1
  1125
*  Constraint (2) can be written as follows:
alpar@1
  1126
*
alpar@1
  1127
*     sum a[p,j] x[j] = b - a[p,q] x[q].                             (3)
alpar@1
  1128
*     j!=q
alpar@1
  1129
*
alpar@1
  1130
*  According to (1) constraint (3) is equivalent to the following
alpar@1
  1131
*  inequality constraint:
alpar@1
  1132
*
alpar@1
  1133
*     L[p] <= sum a[p,j] x[j] <= U[p],                               (4)
alpar@1
  1134
*             j!=q
alpar@1
  1135
*
alpar@1
  1136
*  where
alpar@1
  1137
*
alpar@1
  1138
*            ( b - a[p,q] u[q],  if a[p,q] > 0
alpar@1
  1139
*     L[p] = <                                                       (5)
alpar@1
  1140
*            ( b - a[p,q] l[q],  if a[p,q] < 0
alpar@1
  1141
*
alpar@1
  1142
*            ( b - a[p,q] l[q],  if a[p,q] > 0
alpar@1
  1143
*     U[p] = <                                                       (6)
alpar@1
  1144
*            ( b - a[p,q] u[q],  if a[p,q] < 0
alpar@1
  1145
*
alpar@1
  1146
*  From (2) it follows that:
alpar@1
  1147
*
alpar@1
  1148
*              1
alpar@1
  1149
*     x[q] = ------ (b - sum a[p,j] x[j]).                           (7)
alpar@1
  1150
*            a[p,q]      j!=q
alpar@1
  1151
*
alpar@1
  1152
*  In order to eliminate x[q] from the objective row we substitute it
alpar@1
  1153
*  from (6) to that row:
alpar@1
  1154
*
alpar@1
  1155
*     z = sum c[j] x[j] + c[q] x[q] + c[0] =
alpar@1
  1156
*         j!=q
alpar@1
  1157
*                                 1
alpar@1
  1158
*       = sum c[j] x[j] + c[q] [------ (b - sum a[p,j] x[j])] + c0 =
alpar@1
  1159
*         j!=q                  a[p,q]      j!=q
alpar@1
  1160
*
alpar@1
  1161
*       = sum c~[j] x[j] + c~[0],
alpar@1
  1162
*         j!=q
alpar@1
  1163
*                         a[p,j]                     b
alpar@1
  1164
*     c~[j] = c[j] - c[q] ------,  c~0 = c0 - c[q] ------            (8)
alpar@1
  1165
*                         a[p,q]                   a[p,q]
alpar@1
  1166
*
alpar@1
  1167
*  are values of objective coefficients and constant term, resp., in
alpar@1
  1168
*  the transformed problem.
alpar@1
  1169
*
alpar@1
  1170
*  Note that column q is column singleton, so in the dual system of the
alpar@1
  1171
*  original problem it corresponds to the following row singleton:
alpar@1
  1172
*
alpar@1
  1173
*     a[p,q] pi[p] + lambda[q] = c[q].                               (9)
alpar@1
  1174
*
alpar@1
  1175
*  In the transformed problem row (9) would be the following:
alpar@1
  1176
*
alpar@1
  1177
*     a[p,q] pi~[p] + lambda[q] = c~[q] = 0.                        (10)
alpar@1
  1178
*
alpar@1
  1179
*  Subtracting (10) from (9) we have:
alpar@1
  1180
*
alpar@1
  1181
*     a[p,q] (pi[p] - pi~[p]) = c[q]
alpar@1
  1182
*
alpar@1
  1183
*  that gives the following formula to compute multiplier for row p in
alpar@1
  1184
*  solution to the original problem using its value in solution to the
alpar@1
  1185
*  transformed problem:
alpar@1
  1186
*
alpar@1
  1187
*     pi[p] = pi~[p] + c[q] / a[p,q].                               (11)
alpar@1
  1188
*
alpar@1
  1189
*  RECOVERING BASIC SOLUTION
alpar@1
  1190
*
alpar@1
  1191
*  Status of column q in solution to the original problem is defined
alpar@1
  1192
*  by status of row p in solution to the transformed problem and the
alpar@1
  1193
*  sign of coefficient a[p,q] in the original inequality constraint (2)
alpar@1
  1194
*  as follows:
alpar@1
  1195
*
alpar@1
  1196
*     +-----------------------+---------+--------------------+
alpar@1
  1197
*     |    Status of row p    | Sign of | Status of column q |
alpar@1
  1198
*     | (transformed problem) | a[p,q]  | (original problem) |
alpar@1
  1199
*     +-----------------------+---------+--------------------+
alpar@1
  1200
*     |        GLP_BS         |  + / -  |       GLP_BS       |
alpar@1
  1201
*     |        GLP_NL         |    +    |       GLP_NU       |
alpar@1
  1202
*     |        GLP_NL         |    -    |       GLP_NL       |
alpar@1
  1203
*     |        GLP_NU         |    +    |       GLP_NL       |
alpar@1
  1204
*     |        GLP_NU         |    -    |       GLP_NU       |
alpar@1
  1205
*     |        GLP_NF         |  + / -  |       GLP_NF       |
alpar@1
  1206
*     +-----------------------+---------+--------------------+
alpar@1
  1207
*
alpar@1
  1208
*  Value of column q is computed with formula (7). Since originally row
alpar@1
  1209
*  p is equality constraint, its status is assigned GLP_NS, and value of
alpar@1
  1210
*  its multiplier pi[p] is computed with formula (11).
alpar@1
  1211
*
alpar@1
  1212
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  1213
*
alpar@1
  1214
*  Value of column q is computed with formula (7). Row multiplier value
alpar@1
  1215
*  pi[p] is computed with formula (11).
alpar@1
  1216
*
alpar@1
  1217
*  RECOVERING MIP SOLUTION
alpar@1
  1218
*
alpar@1
  1219
*  Value of column q is computed with formula (7). */
alpar@1
  1220
alpar@1
  1221
struct implied_slack
alpar@1
  1222
{     /* column singleton (implied slack variable) */
alpar@1
  1223
      int p;
alpar@1
  1224
      /* row reference number */
alpar@1
  1225
      int q;
alpar@1
  1226
      /* column reference number */
alpar@1
  1227
      double apq;
alpar@1
  1228
      /* constraint coefficient a[p,q] */
alpar@1
  1229
      double b;
alpar@1
  1230
      /* right-hand side of original equality constraint */
alpar@1
  1231
      double c;
alpar@1
  1232
      /* original objective coefficient at x[q] */
alpar@1
  1233
      NPPLFE *ptr;
alpar@1
  1234
      /* list of non-zero coefficients a[p,j], j != q */
alpar@1
  1235
};
alpar@1
  1236
alpar@1
  1237
static int rcv_implied_slack(NPP *npp, void *info);
alpar@1
  1238
alpar@1
  1239
void npp_implied_slack(NPP *npp, NPPCOL *q)
alpar@1
  1240
{     /* process column singleton (implied slack variable) */
alpar@1
  1241
      struct implied_slack *info;
alpar@1
  1242
      NPPROW *p;
alpar@1
  1243
      NPPAIJ *aij;
alpar@1
  1244
      NPPLFE *lfe;
alpar@1
  1245
      /* the column must be non-integral non-fixed singleton */
alpar@1
  1246
      xassert(!q->is_int);
alpar@1
  1247
      xassert(q->lb < q->ub);
alpar@1
  1248
      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
alpar@1
  1249
      /* corresponding row must be equality constraint */
alpar@1
  1250
      aij = q->ptr;
alpar@1
  1251
      p = aij->row;
alpar@1
  1252
      xassert(p->lb == p->ub);
alpar@1
  1253
      /* create transformation stack entry */
alpar@1
  1254
      info = npp_push_tse(npp,
alpar@1
  1255
         rcv_implied_slack, sizeof(struct implied_slack));
alpar@1
  1256
      info->p = p->i;
alpar@1
  1257
      info->q = q->j;
alpar@1
  1258
      info->apq = aij->val;
alpar@1
  1259
      info->b = p->lb;
alpar@1
  1260
      info->c = q->coef;
alpar@1
  1261
      info->ptr = NULL;
alpar@1
  1262
      /* save row coefficients a[p,j], j != q, and substitute x[q]
alpar@1
  1263
         into the objective row */
alpar@1
  1264
      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  1265
      {  if (aij->col == q) continue; /* skip a[p,q] */
alpar@1
  1266
         lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
  1267
         lfe->ref = aij->col->j;
alpar@1
  1268
         lfe->val = aij->val;
alpar@1
  1269
         lfe->next = info->ptr;
alpar@1
  1270
         info->ptr = lfe;
alpar@1
  1271
         aij->col->coef -= info->c * (aij->val / info->apq);
alpar@1
  1272
      }
alpar@1
  1273
      npp->c0 += info->c * (info->b / info->apq);
alpar@1
  1274
      /* compute new row bounds */
alpar@1
  1275
      if (info->apq > 0.0)
alpar@1
  1276
      {  p->lb = (q->ub == +DBL_MAX ?
alpar@1
  1277
            -DBL_MAX : info->b - info->apq * q->ub);
alpar@1
  1278
         p->ub = (q->lb == -DBL_MAX ?
alpar@1
  1279
            +DBL_MAX : info->b - info->apq * q->lb);
alpar@1
  1280
      }
alpar@1
  1281
      else
alpar@1
  1282
      {  p->lb = (q->lb == -DBL_MAX ?
alpar@1
  1283
            -DBL_MAX : info->b - info->apq * q->lb);
alpar@1
  1284
         p->ub = (q->ub == +DBL_MAX ?
alpar@1
  1285
            +DBL_MAX : info->b - info->apq * q->ub);
alpar@1
  1286
      }
alpar@1
  1287
      /* remove the column from the problem */
alpar@1
  1288
      npp_del_col(npp, q);
alpar@1
  1289
      return;
alpar@1
  1290
}
alpar@1
  1291
alpar@1
  1292
static int rcv_implied_slack(NPP *npp, void *_info)
alpar@1
  1293
{     /* recover column singleton (implied slack variable) */
alpar@1
  1294
      struct implied_slack *info = _info;
alpar@1
  1295
      NPPLFE *lfe;
alpar@1
  1296
      double temp;
alpar@1
  1297
      if (npp->sol == GLP_SOL)
alpar@1
  1298
      {  /* assign statuses to row p and column q */
alpar@1
  1299
         if (npp->r_stat[info->p] == GLP_BS ||
alpar@1
  1300
             npp->r_stat[info->p] == GLP_NF)
alpar@1
  1301
            npp->c_stat[info->q] = npp->r_stat[info->p];
alpar@1
  1302
         else if (npp->r_stat[info->p] == GLP_NL)
alpar@1
  1303
            npp->c_stat[info->q] =
alpar@1
  1304
               (char)(info->apq > 0.0 ? GLP_NU : GLP_NL);
alpar@1
  1305
         else if (npp->r_stat[info->p] == GLP_NU)
alpar@1
  1306
            npp->c_stat[info->q] =
alpar@1
  1307
               (char)(info->apq > 0.0 ? GLP_NL : GLP_NU);
alpar@1
  1308
         else
alpar@1
  1309
         {  npp_error();
alpar@1
  1310
            return 1;
alpar@1
  1311
         }
alpar@1
  1312
         npp->r_stat[info->p] = GLP_NS;
alpar@1
  1313
      }
alpar@1
  1314
      if (npp->sol != GLP_MIP)
alpar@1
  1315
      {  /* compute multiplier for row p */
alpar@1
  1316
         npp->r_pi[info->p] += info->c / info->apq;
alpar@1
  1317
      }
alpar@1
  1318
      /* compute value of column q */
alpar@1
  1319
      temp = info->b;
alpar@1
  1320
      for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
  1321
         temp -= lfe->val * npp->c_value[lfe->ref];
alpar@1
  1322
      npp->c_value[info->q] = temp / info->apq;
alpar@1
  1323
      return 0;
alpar@1
  1324
}
alpar@1
  1325
alpar@1
  1326
/***********************************************************************
alpar@1
  1327
*  NAME
alpar@1
  1328
*
alpar@1
  1329
*  npp_implied_free - process column singleton (implied free variable)
alpar@1
  1330
*
alpar@1
  1331
*  SYNOPSIS
alpar@1
  1332
*
alpar@1
  1333
*  #include "glpnpp.h"
alpar@1
  1334
*  int npp_implied_free(NPP *npp, NPPCOL *q);
alpar@1
  1335
*
alpar@1
  1336
*  DESCRIPTION
alpar@1
  1337
*
alpar@1
  1338
*  The routine npp_implied_free processes column q:
alpar@1
  1339
*
alpar@1
  1340
*     l[q] <= x[q] <= u[q],                                          (1)
alpar@1
  1341
*
alpar@1
  1342
*  having non-zero coefficient in the only row p, which is inequality
alpar@1
  1343
*  constraint:
alpar@1
  1344
*
alpar@1
  1345
*     L[p] <= sum a[p,j] x[j] + a[p,q] x[q] <= U[p],                 (2)
alpar@1
  1346
*             j!=q
alpar@1
  1347
*
alpar@1
  1348
*  where l[q] < u[q], L[p] < U[p], L[p] > -oo and/or U[p] < +oo.
alpar@1
  1349
*
alpar@1
  1350
*  RETURNS
alpar@1
  1351
*
alpar@1
  1352
*  0 - success;
alpar@1
  1353
*
alpar@1
  1354
*  1 - column lower and/or upper bound(s) can be active;
alpar@1
  1355
*
alpar@1
  1356
*  2 - problem has no dual feasible solution.
alpar@1
  1357
*
alpar@1
  1358
*  PROBLEM TRANSFORMATION
alpar@1
  1359
*
alpar@1
  1360
*  Constraint (2) can be written as follows:
alpar@1
  1361
*
alpar@1
  1362
*     L[p] - sum a[p,j] x[j] <= a[p,q] x[q] <= U[p] - sum a[p,j] x[j],
alpar@1
  1363
*            j!=q                                     j!=q
alpar@1
  1364
*
alpar@1
  1365
*  from which it follows that:
alpar@1
  1366
*
alpar@1
  1367
*     alfa <= a[p,q] x[q] <= beta,                                   (3)
alpar@1
  1368
*
alpar@1
  1369
*  where
alpar@1
  1370
*
alpar@1
  1371
*     alfa = inf(L[p] - sum a[p,j] x[j]) =
alpar@1
  1372
*                       j!=q
alpar@1
  1373
*
alpar@1
  1374
*          = L[p] - sup sum a[p,j] x[j] =                            (4)
alpar@1
  1375
*                       j!=q
alpar@1
  1376
*
alpar@1
  1377
*          = L[p] -  sum  a[p,j] u[j] -  sum  a[p,j] l[j],
alpar@1
  1378
*                  j in Jp             j in Jn
alpar@1
  1379
*
alpar@1
  1380
*     beta = sup(L[p] - sum a[p,j] x[j]) =
alpar@1
  1381
*                       j!=q
alpar@1
  1382
*
alpar@1
  1383
*          = L[p] - inf sum a[p,j] x[j] =                            (5)
alpar@1
  1384
*                       j!=q
alpar@1
  1385
*
alpar@1
  1386
*          = L[p] -  sum  a[p,j] l[j] -  sum  a[p,j] u[j],
alpar@1
  1387
*                  j in Jp             j in Jn
alpar@1
  1388
*
alpar@1
  1389
*     Jp = {j != q: a[p,j] > 0},  Jn = {j != q: a[p,j] < 0}.         (6)
alpar@1
  1390
*
alpar@1
  1391
*  Inequality (3) defines implied bounds of variable x[q]:
alpar@1
  1392
*
alpar@1
  1393
*     l'[q] <= x[q] <= u'[q],                                        (7)
alpar@1
  1394
*
alpar@1
  1395
*  where
alpar@1
  1396
*
alpar@1
  1397
*             ( alfa / a[p,q], if a[p,q] > 0
alpar@1
  1398
*     l'[q] = <                                                     (8a)
alpar@1
  1399
*             ( beta / a[p,q], if a[p,q] < 0
alpar@1
  1400
*
alpar@1
  1401
*             ( beta / a[p,q], if a[p,q] > 0
alpar@1
  1402
*     u'[q] = <                                                     (8b)
alpar@1
  1403
*             ( alfa / a[p,q], if a[p,q] < 0
alpar@1
  1404
*
alpar@1
  1405
*  Thus, if l'[q] > l[q] - eps and u'[q] < u[q] + eps, where eps is
alpar@1
  1406
*  an absolute tolerance for column value, column bounds (1) cannot be
alpar@1
  1407
*  active, in which case column q can be replaced by equivalent free
alpar@1
  1408
*  (unbounded) column.
alpar@1
  1409
*
alpar@1
  1410
*  Note that column q is column singleton, so in the dual system of the
alpar@1
  1411
*  original problem it corresponds to the following row singleton:
alpar@1
  1412
*
alpar@1
  1413
*     a[p,q] pi[p] + lambda[q] = c[q],                               (9)
alpar@1
  1414
*
alpar@1
  1415
*  from which it follows that:
alpar@1
  1416
*
alpar@1
  1417
*     pi[p] = (c[q] - lambda[q]) / a[p,q].                          (10)
alpar@1
  1418
*
alpar@1
  1419
*  Let x[q] be implied free (unbounded) variable. Then column q can be
alpar@1
  1420
*  only basic, so its multiplier lambda[q] is equal to zero, and from
alpar@1
  1421
*  (10) we have:
alpar@1
  1422
*
alpar@1
  1423
*     pi[p] = c[q] / a[p,q].                                        (11)
alpar@1
  1424
*
alpar@1
  1425
*  There are possible three cases:
alpar@1
  1426
*
alpar@1
  1427
*  1) pi[p] < -eps, where eps is an absolute tolerance for row
alpar@1
  1428
*     multiplier. In this case, to provide dual feasibility of the
alpar@1
  1429
*     original problem, row p must be active on its lower bound, and
alpar@1
  1430
*     if its lower bound does not exist (L[p] = -oo), the problem has
alpar@1
  1431
*     no dual feasible solution;
alpar@1
  1432
*
alpar@1
  1433
*  2) pi[p] > +eps. In this case row p must be active on its upper
alpar@1
  1434
*     bound, and if its upper bound does not exist (U[p] = +oo), the
alpar@1
  1435
*     problem has no dual feasible solution;
alpar@1
  1436
*
alpar@1
  1437
*  3) -eps <= pi[p] <= +eps. In this case any (either lower or upper)
alpar@1
  1438
*     bound of row p can be active, because this does not affect dual
alpar@1
  1439
*     feasibility.
alpar@1
  1440
*
alpar@1
  1441
*  Thus, in all three cases original inequality constraint (2) can be
alpar@1
  1442
*  replaced by equality constraint, where the right-hand side is either
alpar@1
  1443
*  lower or upper bound of row p, and bounds of column q can be removed
alpar@1
  1444
*  that makes it free (unbounded). (May note that this transformation
alpar@1
  1445
*  can be followed by transformation "Column singleton (implied slack
alpar@1
  1446
*  variable)" performed by the routine npp_implied_slack.)
alpar@1
  1447
*
alpar@1
  1448
*  RECOVERING BASIC SOLUTION
alpar@1
  1449
*
alpar@1
  1450
*  Status of row p in solution to the original problem is determined
alpar@1
  1451
*  by its status in solution to the transformed problem and its bound,
alpar@1
  1452
*  which was choosen to be active:
alpar@1
  1453
*
alpar@1
  1454
*     +-----------------------+--------+--------------------+
alpar@1
  1455
*     |    Status of row p    | Active | Status of row p    |
alpar@1
  1456
*     | (transformed problem) | bound  | (original problem) |
alpar@1
  1457
*     +-----------------------+--------+--------------------+
alpar@1
  1458
*     |        GLP_BS         |  L[p]  |       GLP_BS       |
alpar@1
  1459
*     |        GLP_BS         |  U[p]  |       GLP_BS       |
alpar@1
  1460
*     |        GLP_NS         |  L[p]  |       GLP_NL       |
alpar@1
  1461
*     |        GLP_NS         |  U[p]  |       GLP_NU       |
alpar@1
  1462
*     +-----------------------+--------+--------------------+
alpar@1
  1463
*
alpar@1
  1464
*  Value of row multiplier pi[p] (as well as value of column q) in
alpar@1
  1465
*  solution to the original problem is the same as in solution to the
alpar@1
  1466
*  transformed problem.
alpar@1
  1467
*
alpar@1
  1468
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  1469
*
alpar@1
  1470
*  Value of row multiplier pi[p] in solution to the original problem is
alpar@1
  1471
*  the same as in solution to the transformed problem.
alpar@1
  1472
*
alpar@1
  1473
*  RECOVERING MIP SOLUTION
alpar@1
  1474
*
alpar@1
  1475
*  None needed. */
alpar@1
  1476
alpar@1
  1477
struct implied_free
alpar@1
  1478
{     /* column singleton (implied free variable) */
alpar@1
  1479
      int p;
alpar@1
  1480
      /* row reference number */
alpar@1
  1481
      char stat;
alpar@1
  1482
      /* row status:
alpar@1
  1483
         GLP_NL - active constraint on lower bound
alpar@1
  1484
         GLP_NU - active constraint on upper bound */
alpar@1
  1485
};
alpar@1
  1486
alpar@1
  1487
static int rcv_implied_free(NPP *npp, void *info);
alpar@1
  1488
alpar@1
  1489
int npp_implied_free(NPP *npp, NPPCOL *q)
alpar@1
  1490
{     /* process column singleton (implied free variable) */
alpar@1
  1491
      struct implied_free *info;
alpar@1
  1492
      NPPROW *p;
alpar@1
  1493
      NPPAIJ *apq, *aij;
alpar@1
  1494
      double alfa, beta, l, u, pi, eps;
alpar@1
  1495
      /* the column must be non-fixed singleton */
alpar@1
  1496
      xassert(q->lb < q->ub);
alpar@1
  1497
      xassert(q->ptr != NULL && q->ptr->c_next == NULL);
alpar@1
  1498
      /* corresponding row must be inequality constraint */
alpar@1
  1499
      apq = q->ptr;
alpar@1
  1500
      p = apq->row;
alpar@1
  1501
      xassert(p->lb != -DBL_MAX || p->ub != +DBL_MAX);
alpar@1
  1502
      xassert(p->lb < p->ub);
alpar@1
  1503
      /* compute alfa */
alpar@1
  1504
      alfa = p->lb;
alpar@1
  1505
      if (alfa != -DBL_MAX)
alpar@1
  1506
      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  1507
         {  if (aij == apq) continue; /* skip a[p,q] */
alpar@1
  1508
            if (aij->val > 0.0)
alpar@1
  1509
            {  if (aij->col->ub == +DBL_MAX)
alpar@1
  1510
               {  alfa = -DBL_MAX;
alpar@1
  1511
                  break;
alpar@1
  1512
               }
alpar@1
  1513
               alfa -= aij->val * aij->col->ub;
alpar@1
  1514
            }
alpar@1
  1515
            else /* < 0.0 */
alpar@1
  1516
            {  if (aij->col->lb == -DBL_MAX)
alpar@1
  1517
               {  alfa = -DBL_MAX;
alpar@1
  1518
                  break;
alpar@1
  1519
               }
alpar@1
  1520
               alfa -= aij->val * aij->col->lb;
alpar@1
  1521
            }
alpar@1
  1522
         }
alpar@1
  1523
      }
alpar@1
  1524
      /* compute beta */
alpar@1
  1525
      beta = p->ub;
alpar@1
  1526
      if (beta != +DBL_MAX)
alpar@1
  1527
      {  for (aij = p->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  1528
         {  if (aij == apq) continue; /* skip a[p,q] */
alpar@1
  1529
            if (aij->val > 0.0)
alpar@1
  1530
            {  if (aij->col->lb == -DBL_MAX)
alpar@1
  1531
               {  beta = +DBL_MAX;
alpar@1
  1532
                  break;
alpar@1
  1533
               }
alpar@1
  1534
               beta -= aij->val * aij->col->lb;
alpar@1
  1535
            }
alpar@1
  1536
            else /* < 0.0 */
alpar@1
  1537
            {  if (aij->col->ub == +DBL_MAX)
alpar@1
  1538
               {  beta = +DBL_MAX;
alpar@1
  1539
                  break;
alpar@1
  1540
               }
alpar@1
  1541
               beta -= aij->val * aij->col->ub;
alpar@1
  1542
            }
alpar@1
  1543
         }
alpar@1
  1544
      }
alpar@1
  1545
      /* compute implied column lower bound l'[q] */
alpar@1
  1546
      if (apq->val > 0.0)
alpar@1
  1547
         l = (alfa == -DBL_MAX ? -DBL_MAX : alfa / apq->val);
alpar@1
  1548
      else /* < 0.0 */
alpar@1
  1549
         l = (beta == +DBL_MAX ? -DBL_MAX : beta / apq->val);
alpar@1
  1550
      /* compute implied column upper bound u'[q] */
alpar@1
  1551
      if (apq->val > 0.0)
alpar@1
  1552
         u = (beta == +DBL_MAX ? +DBL_MAX : beta / apq->val);
alpar@1
  1553
      else
alpar@1
  1554
         u = (alfa == -DBL_MAX ? +DBL_MAX : alfa / apq->val);
alpar@1
  1555
      /* check if column lower bound l[q] can be active */
alpar@1
  1556
      if (q->lb != -DBL_MAX)
alpar@1
  1557
      {  eps = 1e-9 + 1e-12 * fabs(q->lb);
alpar@1
  1558
         if (l < q->lb - eps) return 1; /* yes, it can */
alpar@1
  1559
      }
alpar@1
  1560
      /* check if column upper bound u[q] can be active */
alpar@1
  1561
      if (q->ub != +DBL_MAX)
alpar@1
  1562
      {  eps = 1e-9 + 1e-12 * fabs(q->ub);
alpar@1
  1563
         if (u > q->ub + eps) return 1; /* yes, it can */
alpar@1
  1564
      }
alpar@1
  1565
      /* okay; make column q free (unbounded) */
alpar@1
  1566
      q->lb = -DBL_MAX, q->ub = +DBL_MAX;
alpar@1
  1567
      /* create transformation stack entry */
alpar@1
  1568
      info = npp_push_tse(npp,
alpar@1
  1569
         rcv_implied_free, sizeof(struct implied_free));
alpar@1
  1570
      info->p = p->i;
alpar@1
  1571
      info->stat = -1;
alpar@1
  1572
      /* compute row multiplier pi[p] */
alpar@1
  1573
      pi = q->coef / apq->val;
alpar@1
  1574
      /* check dual feasibility for row p */
alpar@1
  1575
      if (pi > +DBL_EPSILON)
alpar@1
  1576
      {  /* lower bound L[p] must be active */
alpar@1
  1577
         if (p->lb != -DBL_MAX)
alpar@1
  1578
nl:      {  info->stat = GLP_NL;
alpar@1
  1579
            p->ub = p->lb;
alpar@1
  1580
         }
alpar@1
  1581
         else
alpar@1
  1582
         {  if (pi > +1e-5) return 2; /* dual infeasibility */
alpar@1
  1583
            /* take a chance on U[p] */
alpar@1
  1584
            xassert(p->ub != +DBL_MAX);
alpar@1
  1585
            goto nu;
alpar@1
  1586
         }
alpar@1
  1587
      }
alpar@1
  1588
      else if (pi < -DBL_EPSILON)
alpar@1
  1589
      {  /* upper bound U[p] must be active */
alpar@1
  1590
         if (p->ub != +DBL_MAX)
alpar@1
  1591
nu:      {  info->stat = GLP_NU;
alpar@1
  1592
            p->lb = p->ub;
alpar@1
  1593
         }
alpar@1
  1594
         else
alpar@1
  1595
         {  if (pi < -1e-5) return 2; /* dual infeasibility */
alpar@1
  1596
            /* take a chance on L[p] */
alpar@1
  1597
            xassert(p->lb != -DBL_MAX);
alpar@1
  1598
            goto nl;
alpar@1
  1599
         }
alpar@1
  1600
      }
alpar@1
  1601
      else
alpar@1
  1602
      {  /* any bound (either L[p] or U[p]) can be made active  */
alpar@1
  1603
         if (p->ub == +DBL_MAX)
alpar@1
  1604
         {  xassert(p->lb != -DBL_MAX);
alpar@1
  1605
            goto nl;
alpar@1
  1606
         }
alpar@1
  1607
         if (p->lb == -DBL_MAX)
alpar@1
  1608
         {  xassert(p->ub != +DBL_MAX);
alpar@1
  1609
            goto nu;
alpar@1
  1610
         }
alpar@1
  1611
         if (fabs(p->lb) <= fabs(p->ub)) goto nl; else goto nu;
alpar@1
  1612
      }
alpar@1
  1613
      return 0;
alpar@1
  1614
}
alpar@1
  1615
alpar@1
  1616
static int rcv_implied_free(NPP *npp, void *_info)
alpar@1
  1617
{     /* recover column singleton (implied free variable) */
alpar@1
  1618
      struct implied_free *info = _info;
alpar@1
  1619
      if (npp->sol == GLP_SOL)
alpar@1
  1620
      {  if (npp->r_stat[info->p] == GLP_BS)
alpar@1
  1621
            npp->r_stat[info->p] = GLP_BS;
alpar@1
  1622
         else if (npp->r_stat[info->p] == GLP_NS)
alpar@1
  1623
         {  xassert(info->stat == GLP_NL || info->stat == GLP_NU);
alpar@1
  1624
            npp->r_stat[info->p] = info->stat;
alpar@1
  1625
         }
alpar@1
  1626
         else
alpar@1
  1627
         {  npp_error();
alpar@1
  1628
            return 1;
alpar@1
  1629
         }
alpar@1
  1630
      }
alpar@1
  1631
      return 0;
alpar@1
  1632
}
alpar@1
  1633
alpar@1
  1634
/***********************************************************************
alpar@1
  1635
*  NAME
alpar@1
  1636
*
alpar@1
  1637
*  npp_eq_doublet - process row doubleton (equality constraint)
alpar@1
  1638
*
alpar@1
  1639
*  SYNOPSIS
alpar@1
  1640
*
alpar@1
  1641
*  #include "glpnpp.h"
alpar@1
  1642
*  NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p);
alpar@1
  1643
*
alpar@1
  1644
*  DESCRIPTION
alpar@1
  1645
*
alpar@1
  1646
*  The routine npp_eq_doublet processes row p, which is equality
alpar@1
  1647
*  constraint having exactly two non-zero coefficients:
alpar@1
  1648
*
alpar@1
  1649
*     a[p,q] x[q] + a[p,r] x[r] = b.                                 (1)
alpar@1
  1650
*
alpar@1
  1651
*  As the result of processing one of columns q or r is eliminated from
alpar@1
  1652
*  all other rows and, thus, becomes column singleton of type "implied
alpar@1
  1653
*  slack variable". Row p is not changed and along with column q and r
alpar@1
  1654
*  remains in the problem.
alpar@1
  1655
*
alpar@1
  1656
*  RETURNS
alpar@1
  1657
*
alpar@1
  1658
*  The routine npp_eq_doublet returns pointer to the descriptor of that
alpar@1
  1659
*  column q or r which has been eliminated. If, due to some reason, the
alpar@1
  1660
*  elimination was not performed, the routine returns NULL.
alpar@1
  1661
*
alpar@1
  1662
*  PROBLEM TRANSFORMATION
alpar@1
  1663
*
alpar@1
  1664
*  First, we decide which column q or r will be eliminated. Let it be
alpar@1
  1665
*  column q. Consider i-th constraint row, where column q has non-zero
alpar@1
  1666
*  coefficient a[i,q] != 0:
alpar@1
  1667
*
alpar@1
  1668
*     L[i] <= sum a[i,j] x[j] <= U[i].                               (2)
alpar@1
  1669
*              j
alpar@1
  1670
*
alpar@1
  1671
*  In order to eliminate column q from row (2) we subtract from it row
alpar@1
  1672
*  (1) multiplied by gamma[i] = a[i,q] / a[p,q], i.e. we replace in the
alpar@1
  1673
*  transformed problem row (2) by its linear combination with row (1).
alpar@1
  1674
*  This transformation changes only coefficients in columns q and r,
alpar@1
  1675
*  and bounds of row i as follows:
alpar@1
  1676
*
alpar@1
  1677
*     a~[i,q] = a[i,q] - gamma[i] a[p,q] = 0,                        (3)
alpar@1
  1678
*
alpar@1
  1679
*     a~[i,r] = a[i,r] - gamma[i] a[p,r],                            (4)
alpar@1
  1680
*
alpar@1
  1681
*       L~[i] = L[i] - gamma[i] b,                                   (5)
alpar@1
  1682
*
alpar@1
  1683
*       U~[i] = U[i] - gamma[i] b.                                   (6)
alpar@1
  1684
*
alpar@1
  1685
*  RECOVERING BASIC SOLUTION
alpar@1
  1686
*
alpar@1
  1687
*  The transformation of the primal system of the original problem:
alpar@1
  1688
*
alpar@1
  1689
*     L <= A x <= U                                                  (7)
alpar@1
  1690
*
alpar@1
  1691
*  is equivalent to multiplying from the left a transformation matrix F
alpar@1
  1692
*  by components of this primal system, which in the transformed problem
alpar@1
  1693
*  becomes the following:
alpar@1
  1694
*
alpar@1
  1695
*     F L <= F A x <= F U  ==>  L~ <= A~x <= U~.                     (8)
alpar@1
  1696
*
alpar@1
  1697
*  The matrix F has the following structure:
alpar@1
  1698
*
alpar@1
  1699
*         ( 1           -gamma[1]            )
alpar@1
  1700
*         (                                  )
alpar@1
  1701
*         (    1        -gamma[2]            )
alpar@1
  1702
*         (                                  )
alpar@1
  1703
*         (      ...       ...               )
alpar@1
  1704
*         (                                  )
alpar@1
  1705
*     F = (          1  -gamma[p-1]          )                       (9)
alpar@1
  1706
*         (                                  )
alpar@1
  1707
*         (                 1                )
alpar@1
  1708
*         (                                  )
alpar@1
  1709
*         (             -gamma[p+1]  1       )
alpar@1
  1710
*         (                                  )
alpar@1
  1711
*         (                ...          ...  )
alpar@1
  1712
*
alpar@1
  1713
*  where its column containing elements -gamma[i] corresponds to row p
alpar@1
  1714
*  of the primal system.
alpar@1
  1715
*
alpar@1
  1716
*  From (8) it follows that the dual system of the original problem:
alpar@1
  1717
*
alpar@1
  1718
*     A'pi + lambda = c,                                            (10)
alpar@1
  1719
*
alpar@1
  1720
*  in the transformed problem becomes the following:
alpar@1
  1721
*
alpar@1
  1722
*     A'F'inv(F')pi + lambda = c  ==>  (A~)'pi~ + lambda = c,       (11)
alpar@1
  1723
*
alpar@1
  1724
*  where:
alpar@1
  1725
*
alpar@1
  1726
*     pi~ = inv(F')pi                                               (12)
alpar@1
  1727
*
alpar@1
  1728
*  is the vector of row multipliers in the transformed problem. Thus:
alpar@1
  1729
*
alpar@1
  1730
*     pi = F'pi~.                                                   (13)
alpar@1
  1731
*
alpar@1
  1732
*  Therefore, as it follows from (13), value of multiplier for row p in
alpar@1
  1733
*  solution to the original problem can be computed as follows:
alpar@1
  1734
*
alpar@1
  1735
*     pi[p] = pi~[p] - sum gamma[i] pi~[i],                         (14)
alpar@1
  1736
*                       i
alpar@1
  1737
*
alpar@1
  1738
*  where pi~[i] = pi[i] is multiplier for row i (i != p).
alpar@1
  1739
*
alpar@1
  1740
*  Note that the statuses of all rows and columns are not changed.
alpar@1
  1741
*
alpar@1
  1742
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  1743
*
alpar@1
  1744
*  Multiplier for row p in solution to the original problem is computed
alpar@1
  1745
*  with formula (14).
alpar@1
  1746
*
alpar@1
  1747
*  RECOVERING MIP SOLUTION
alpar@1
  1748
*
alpar@1
  1749
*  None needed. */
alpar@1
  1750
alpar@1
  1751
struct eq_doublet
alpar@1
  1752
{     /* row doubleton (equality constraint) */
alpar@1
  1753
      int p;
alpar@1
  1754
      /* row reference number */
alpar@1
  1755
      double apq;
alpar@1
  1756
      /* constraint coefficient a[p,q] */
alpar@1
  1757
      NPPLFE *ptr;
alpar@1
  1758
      /* list of non-zero coefficients a[i,q], i != p */
alpar@1
  1759
};
alpar@1
  1760
alpar@1
  1761
static int rcv_eq_doublet(NPP *npp, void *info);
alpar@1
  1762
alpar@1
  1763
NPPCOL *npp_eq_doublet(NPP *npp, NPPROW *p)
alpar@1
  1764
{     /* process row doubleton (equality constraint) */
alpar@1
  1765
      struct eq_doublet *info;
alpar@1
  1766
      NPPROW *i;
alpar@1
  1767
      NPPCOL *q, *r;
alpar@1
  1768
      NPPAIJ *apq, *apr, *aiq, *air, *next;
alpar@1
  1769
      NPPLFE *lfe;
alpar@1
  1770
      double gamma;
alpar@1
  1771
      /* the row must be doubleton equality constraint */
alpar@1
  1772
      xassert(p->lb == p->ub);
alpar@1
  1773
      xassert(p->ptr != NULL && p->ptr->r_next != NULL &&
alpar@1
  1774
              p->ptr->r_next->r_next == NULL);
alpar@1
  1775
      /* choose column to be eliminated */
alpar@1
  1776
      {  NPPAIJ *a1, *a2;
alpar@1
  1777
         a1 = p->ptr, a2 = a1->r_next;
alpar@1
  1778
         if (fabs(a2->val) < 0.001 * fabs(a1->val))
alpar@1
  1779
         {  /* only first column can be eliminated, because second one
alpar@1
  1780
               has too small constraint coefficient */
alpar@1
  1781
            apq = a1, apr = a2;
alpar@1
  1782
         }
alpar@1
  1783
         else if (fabs(a1->val) < 0.001 * fabs(a2->val))
alpar@1
  1784
         {  /* only second column can be eliminated, because first one
alpar@1
  1785
               has too small constraint coefficient */
alpar@1
  1786
            apq = a2, apr = a1;
alpar@1
  1787
         }
alpar@1
  1788
         else
alpar@1
  1789
         {  /* both columns are appropriate; choose that one which is
alpar@1
  1790
               shorter to minimize fill-in */
alpar@1
  1791
            if (npp_col_nnz(npp, a1->col) <= npp_col_nnz(npp, a2->col))
alpar@1
  1792
            {  /* first column is shorter */
alpar@1
  1793
               apq = a1, apr = a2;
alpar@1
  1794
            }
alpar@1
  1795
            else
alpar@1
  1796
            {  /* second column is shorter */
alpar@1
  1797
               apq = a2, apr = a1;
alpar@1
  1798
            }
alpar@1
  1799
         }
alpar@1
  1800
      }
alpar@1
  1801
      /* now columns q and r have been chosen */
alpar@1
  1802
      q = apq->col, r = apr->col;
alpar@1
  1803
      /* create transformation stack entry */
alpar@1
  1804
      info = npp_push_tse(npp,
alpar@1
  1805
         rcv_eq_doublet, sizeof(struct eq_doublet));
alpar@1
  1806
      info->p = p->i;
alpar@1
  1807
      info->apq = apq->val;
alpar@1
  1808
      info->ptr = NULL;
alpar@1
  1809
      /* transform each row i (i != p), where a[i,q] != 0, to eliminate
alpar@1
  1810
         column q */
alpar@1
  1811
      for (aiq = q->ptr; aiq != NULL; aiq = next)
alpar@1
  1812
      {  next = aiq->c_next;
alpar@1
  1813
         if (aiq == apq) continue; /* skip row p */
alpar@1
  1814
         i = aiq->row; /* row i to be transformed */
alpar@1
  1815
         /* save constraint coefficient a[i,q] */
alpar@1
  1816
         if (npp->sol != GLP_MIP)
alpar@1
  1817
         {  lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
  1818
            lfe->ref = i->i;
alpar@1
  1819
            lfe->val = aiq->val;
alpar@1
  1820
            lfe->next = info->ptr;
alpar@1
  1821
            info->ptr = lfe;
alpar@1
  1822
         }
alpar@1
  1823
         /* find coefficient a[i,r] in row i */
alpar@1
  1824
         for (air = i->ptr; air != NULL; air = air->r_next)
alpar@1
  1825
            if (air->col == r) break;
alpar@1
  1826
         /* if a[i,r] does not exist, create a[i,r] = 0 */
alpar@1
  1827
         if (air == NULL)
alpar@1
  1828
            air = npp_add_aij(npp, i, r, 0.0);
alpar@1
  1829
         /* compute gamma[i] = a[i,q] / a[p,q] */
alpar@1
  1830
         gamma = aiq->val / apq->val;
alpar@1
  1831
         /* (row i) := (row i) - gamma[i] * (row p); see (3)-(6) */
alpar@1
  1832
         /* new a[i,q] is exact zero due to elimnation; remove it from
alpar@1
  1833
            row i */
alpar@1
  1834
         npp_del_aij(npp, aiq);
alpar@1
  1835
         /* compute new a[i,r] */
alpar@1
  1836
         air->val -= gamma * apr->val;
alpar@1
  1837
         /* if new a[i,r] is close to zero due to numeric cancelation,
alpar@1
  1838
            remove it from row i */
alpar@1
  1839
         if (fabs(air->val) <= 1e-10)
alpar@1
  1840
            npp_del_aij(npp, air);
alpar@1
  1841
         /* compute new lower and upper bounds of row i */
alpar@1
  1842
         if (i->lb == i->ub)
alpar@1
  1843
            i->lb = i->ub = (i->lb - gamma * p->lb);
alpar@1
  1844
         else
alpar@1
  1845
         {  if (i->lb != -DBL_MAX)
alpar@1
  1846
               i->lb -= gamma * p->lb;
alpar@1
  1847
            if (i->ub != +DBL_MAX)
alpar@1
  1848
               i->ub -= gamma * p->lb;
alpar@1
  1849
         }
alpar@1
  1850
      }
alpar@1
  1851
      return q;
alpar@1
  1852
}
alpar@1
  1853
alpar@1
  1854
static int rcv_eq_doublet(NPP *npp, void *_info)
alpar@1
  1855
{     /* recover row doubleton (equality constraint) */
alpar@1
  1856
      struct eq_doublet *info = _info;
alpar@1
  1857
      NPPLFE *lfe;
alpar@1
  1858
      double gamma, temp;
alpar@1
  1859
      /* we assume that processing row p is followed by processing
alpar@1
  1860
         column q as singleton of type "implied slack variable", in
alpar@1
  1861
         which case row p must always be active equality constraint */
alpar@1
  1862
      if (npp->sol == GLP_SOL)
alpar@1
  1863
      {  if (npp->r_stat[info->p] != GLP_NS)
alpar@1
  1864
         {  npp_error();
alpar@1
  1865
            return 1;
alpar@1
  1866
         }
alpar@1
  1867
      }
alpar@1
  1868
      if (npp->sol != GLP_MIP)
alpar@1
  1869
      {  /* compute value of multiplier for row p; see (14) */
alpar@1
  1870
         temp = npp->r_pi[info->p];
alpar@1
  1871
         for (lfe = info->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
  1872
         {  gamma = lfe->val / info->apq; /* a[i,q] / a[p,q] */
alpar@1
  1873
            temp -= gamma * npp->r_pi[lfe->ref];
alpar@1
  1874
         }
alpar@1
  1875
         npp->r_pi[info->p] = temp;
alpar@1
  1876
      }
alpar@1
  1877
      return 0;
alpar@1
  1878
}
alpar@1
  1879
alpar@1
  1880
/***********************************************************************
alpar@1
  1881
*  NAME
alpar@1
  1882
*
alpar@1
  1883
*  npp_forcing_row - process forcing row
alpar@1
  1884
*
alpar@1
  1885
*  SYNOPSIS
alpar@1
  1886
*
alpar@1
  1887
*  #include "glpnpp.h"
alpar@1
  1888
*  int npp_forcing_row(NPP *npp, NPPROW *p, int at);
alpar@1
  1889
*
alpar@1
  1890
*  DESCRIPTION
alpar@1
  1891
*
alpar@1
  1892
*  The routine npp_forcing row processes row p of general format:
alpar@1
  1893
*
alpar@1
  1894
*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
alpar@1
  1895
*              j
alpar@1
  1896
*
alpar@1
  1897
*     l[j] <= x[j] <= u[j],                                          (2)
alpar@1
  1898
*
alpar@1
  1899
*  where L[p] <= U[p] and l[j] < u[j] for all a[p,j] != 0. It is also
alpar@1
  1900
*  assumed that:
alpar@1
  1901
*
alpar@1
  1902
*  1) if at = 0 then |L[p] - U'[p]| <= eps, where U'[p] is implied
alpar@1
  1903
*     row upper bound (see below), eps is an absolute tolerance for row
alpar@1
  1904
*     value;
alpar@1
  1905
*
alpar@1
  1906
*  2) if at = 1 then |U[p] - L'[p]| <= eps, where L'[p] is implied
alpar@1
  1907
*     row lower bound (see below).
alpar@1
  1908
*
alpar@1
  1909
*  RETURNS
alpar@1
  1910
*
alpar@1
  1911
*  0 - success;
alpar@1
  1912
*
alpar@1
  1913
*  1 - cannot fix columns due to too small constraint coefficients.
alpar@1
  1914
*
alpar@1
  1915
*  PROBLEM TRANSFORMATION
alpar@1
  1916
*
alpar@1
  1917
*  Implied lower and upper bounds of row (1) are determined by bounds
alpar@1
  1918
*  of corresponding columns (variables) as follows:
alpar@1
  1919
*
alpar@1
  1920
*     L'[p] = inf sum a[p,j] x[j] =
alpar@1
  1921
*                  j
alpar@1
  1922
*                                                                    (3)
alpar@1
  1923
*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
alpar@1
  1924
*            j in Jp             j in Jn
alpar@1
  1925
*
alpar@1
  1926
*     U'[p] = sup sum a[p,j] x[j] =
alpar@1
  1927
*                                                                    (4)
alpar@1
  1928
*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
alpar@1
  1929
*            j in Jp             j in Jn
alpar@1
  1930
*
alpar@1
  1931
*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
alpar@1
  1932
*
alpar@1
  1933
*  If L[p] =~ U'[p] (at = 0), solution can be primal feasible only when
alpar@1
  1934
*  all variables take their boundary values as defined by (4):
alpar@1
  1935
*
alpar@1
  1936
*            ( u[j], if j in Jp
alpar@1
  1937
*     x[j] = <                                                       (6)
alpar@1
  1938
*            ( l[j], if j in Jn
alpar@1
  1939
*
alpar@1
  1940
*  Similarly, if U[p] =~ L'[p] (at = 1), solution can be primal feasible
alpar@1
  1941
*  only when all variables take their boundary values as defined by (3):
alpar@1
  1942
*
alpar@1
  1943
*            ( l[j], if j in Jp
alpar@1
  1944
*     x[j] = <                                                       (7)
alpar@1
  1945
*            ( u[j], if j in Jn
alpar@1
  1946
*
alpar@1
  1947
*  Condition (6) or (7) allows fixing all columns (variables x[j])
alpar@1
  1948
*  in row (1) on their bounds and then removing them from the problem
alpar@1
  1949
*  (see the routine npp_fixed_col). Due to this row p becomes redundant,
alpar@1
  1950
*  so it can be replaced by equivalent free (unbounded) row and also
alpar@1
  1951
*  removed from the problem (see the routine npp_free_row).
alpar@1
  1952
*
alpar@1
  1953
*  1. To apply this transformation row (1) should not have coefficients
alpar@1
  1954
*     whose magnitude is too small, i.e. all a[p,j] should satisfy to
alpar@1
  1955
*     the following condition:
alpar@1
  1956
*
alpar@1
  1957
*        |a[p,j]| >= eps * max(1, |a[p,k]|),                         (8)
alpar@1
  1958
*                           k
alpar@1
  1959
*     where eps is a relative tolerance for constraint coefficients.
alpar@1
  1960
*     Otherwise, fixing columns may be numerically unreliable and may
alpar@1
  1961
*     lead to wrong solution.
alpar@1
  1962
*
alpar@1
  1963
*  2. The routine fixes columns and remove bounds of row p, however,
alpar@1
  1964
*     it does not remove the row and columns from the problem.
alpar@1
  1965
*
alpar@1
  1966
*  RECOVERING BASIC SOLUTION
alpar@1
  1967
*
alpar@1
  1968
*  In the transformed problem row p being inactive constraint is
alpar@1
  1969
*  assigned status GLP_BS (as the result of transformation of free
alpar@1
  1970
*  row), and all columns in this row are assigned status GLP_NS (as the
alpar@1
  1971
*  result of transformation of fixed columns).
alpar@1
  1972
*
alpar@1
  1973
*  Note that in the dual system of the transformed (as well as original)
alpar@1
  1974
*  problem every column j in row p corresponds to the following row:
alpar@1
  1975
*
alpar@1
  1976
*     sum  a[i,j] pi[i] + a[p,j] pi[p] + lambda[j] = c[j],           (9)
alpar@1
  1977
*     i!=p
alpar@1
  1978
*
alpar@1
  1979
*  from which it follows that:
alpar@1
  1980
*
alpar@1
  1981
*     lambda[j] = c[j] - sum a[i,j] pi[i] - a[p,j] pi[p].           (10)
alpar@1
  1982
*                        i!=p
alpar@1
  1983
*
alpar@1
  1984
*  In the transformed problem values of all multipliers pi[i] are known
alpar@1
  1985
*  (including pi[i], whose value is zero, since row p is inactive).
alpar@1
  1986
*  Thus, using formula (10) it is possible to compute values of
alpar@1
  1987
*  multipliers lambda[j] for all columns in row p.
alpar@1
  1988
*
alpar@1
  1989
*  Note also that in the original problem all columns in row p are
alpar@1
  1990
*  bounded, not fixed. So status GLP_NS assigned to every such column
alpar@1
  1991
*  must be changed to GLP_NL or GLP_NU depending on which bound the
alpar@1
  1992
*  corresponding column has been fixed. This status change may lead to
alpar@1
  1993
*  dual feasibility violation for solution of the original problem,
alpar@1
  1994
*  because now column multipliers must satisfy to the following
alpar@1
  1995
*  condition:
alpar@1
  1996
*
alpar@1
  1997
*               ( >= 0, if status of column j is GLP_NL,
alpar@1
  1998
*     lambda[j] <                                                   (11)
alpar@1
  1999
*               ( <= 0, if status of column j is GLP_NU.
alpar@1
  2000
*
alpar@1
  2001
*  If this condition holds, solution to the original problem is the
alpar@1
  2002
*  same as to the transformed problem. Otherwise, we have to perform
alpar@1
  2003
*  one degenerate pivoting step of the primal simplex method to obtain
alpar@1
  2004
*  dual feasible (hence, optimal) solution to the original problem as
alpar@1
  2005
*  follows. If, on problem transformation, row p was made active on its
alpar@1
  2006
*  lower bound (case at = 0), we change its status to GLP_NL (or GLP_NS)
alpar@1
  2007
*  and start increasing its multiplier pi[p]. Otherwise, if row p was
alpar@1
  2008
*  made active on its upper bound (case at = 1), we change its status
alpar@1
  2009
*  to GLP_NU (or GLP_NS) and start decreasing pi[p]. From (10) it
alpar@1
  2010
*  follows that:
alpar@1
  2011
*
alpar@1
  2012
*     delta lambda[j] = - a[p,j] * delta pi[p] = - a[p,j] pi[p].    (12)
alpar@1
  2013
*
alpar@1
  2014
*  Simple analysis of formulae (3)-(5) shows that changing pi[p] in the
alpar@1
  2015
*  specified direction causes increasing lambda[j] for every column j
alpar@1
  2016
*  assigned status GLP_NL (delta lambda[j] > 0) and decreasing lambda[j]
alpar@1
  2017
*  for every column j assigned status GLP_NU (delta lambda[j] < 0). It
alpar@1
  2018
*  is understood that once the last lambda[q], which violates condition
alpar@1
  2019
*  (11), has reached zero, multipliers lambda[j] for all columns get
alpar@1
  2020
*  valid signs. Such column q can be determined as follows. Let d[j] be
alpar@1
  2021
*  initial value of lambda[j] (i.e. reduced cost of column j) in the
alpar@1
  2022
*  transformed problem computed with formula (10) when pi[p] = 0. Then
alpar@1
  2023
*  lambda[j] = d[j] + delta lambda[j], and from (12) it follows that
alpar@1
  2024
*  lambda[j] becomes zero if:
alpar@1
  2025
*
alpar@1
  2026
*     delta lambda[j] = - a[p,j] pi[p] = - d[j]  ==>
alpar@1
  2027
*                                                                   (13)
alpar@1
  2028
*     pi[p] = d[j] / a[p,j].
alpar@1
  2029
*
alpar@1
  2030
*  Therefore, the last column q, for which lambda[q] becomes zero, can
alpar@1
  2031
*  be determined from the following condition:
alpar@1
  2032
*
alpar@1
  2033
*     |d[q] / a[p,q]| = max  |pi[p]| = max  |d[j] / a[p,j]|,        (14)
alpar@1
  2034
*                      j in D         j in D
alpar@1
  2035
*
alpar@1
  2036
*  where D is a set of columns j whose, reduced costs d[j] have invalid
alpar@1
  2037
*  signs, i.e. violate condition (11). (Thus, if D is empty, solution
alpar@1
  2038
*  to the original problem is the same as solution to the transformed
alpar@1
  2039
*  problem, and no correction is needed as was noticed above.) In
alpar@1
  2040
*  solution to the original problem column q is assigned status GLP_BS,
alpar@1
  2041
*  since it replaces column of auxiliary variable of row p (becoming
alpar@1
  2042
*  active) in the basis, and multiplier for row p is assigned its new
alpar@1
  2043
*  value, which is pi[p] = d[q] / a[p,q]. Note that due to primal
alpar@1
  2044
*  degeneracy values of all columns having non-zero coefficients in row
alpar@1
  2045
*  p remain unchanged.
alpar@1
  2046
*
alpar@1
  2047
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  2048
*
alpar@1
  2049
*  Value of multiplier pi[p] in solution to the original problem is
alpar@1
  2050
*  corrected in the same way as for basic solution. Values of all
alpar@1
  2051
*  columns having non-zero coefficients in row p remain unchanged.
alpar@1
  2052
*
alpar@1
  2053
*  RECOVERING MIP SOLUTION
alpar@1
  2054
*
alpar@1
  2055
*  None needed. */
alpar@1
  2056
alpar@1
  2057
struct forcing_col
alpar@1
  2058
{     /* column fixed on its bound by forcing row */
alpar@1
  2059
      int j;
alpar@1
  2060
      /* column reference number */
alpar@1
  2061
      char stat;
alpar@1
  2062
      /* original column status:
alpar@1
  2063
         GLP_NL - fixed on lower bound
alpar@1
  2064
         GLP_NU - fixed on upper bound */
alpar@1
  2065
      double a;
alpar@1
  2066
      /* constraint coefficient a[p,j] */
alpar@1
  2067
      double c;
alpar@1
  2068
      /* objective coefficient c[j] */
alpar@1
  2069
      NPPLFE *ptr;
alpar@1
  2070
      /* list of non-zero coefficients a[i,j], i != p */
alpar@1
  2071
      struct forcing_col *next;
alpar@1
  2072
      /* pointer to another column fixed by forcing row */
alpar@1
  2073
};
alpar@1
  2074
alpar@1
  2075
struct forcing_row
alpar@1
  2076
{     /* forcing row */
alpar@1
  2077
      int p;
alpar@1
  2078
      /* row reference number */
alpar@1
  2079
      char stat;
alpar@1
  2080
      /* status assigned to the row if it becomes active:
alpar@1
  2081
         GLP_NS - active equality constraint
alpar@1
  2082
         GLP_NL - inequality constraint with lower bound active
alpar@1
  2083
         GLP_NU - inequality constraint with upper bound active */
alpar@1
  2084
      struct forcing_col *ptr;
alpar@1
  2085
      /* list of all columns having non-zero constraint coefficient
alpar@1
  2086
         a[p,j] in the forcing row */
alpar@1
  2087
};
alpar@1
  2088
alpar@1
  2089
static int rcv_forcing_row(NPP *npp, void *info);
alpar@1
  2090
alpar@1
  2091
int npp_forcing_row(NPP *npp, NPPROW *p, int at)
alpar@1
  2092
{     /* process forcing row */
alpar@1
  2093
      struct forcing_row *info;
alpar@1
  2094
      struct forcing_col *col = NULL;
alpar@1
  2095
      NPPCOL *j;
alpar@1
  2096
      NPPAIJ *apj, *aij;
alpar@1
  2097
      NPPLFE *lfe;
alpar@1
  2098
      double big;
alpar@1
  2099
      xassert(at == 0 || at == 1);
alpar@1
  2100
      /* determine maximal magnitude of the row coefficients */
alpar@1
  2101
      big = 1.0;
alpar@1
  2102
      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2103
         if (big < fabs(apj->val)) big = fabs(apj->val);
alpar@1
  2104
      /* if there are too small coefficients in the row, transformation
alpar@1
  2105
         should not be applied */
alpar@1
  2106
      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2107
         if (fabs(apj->val) < 1e-7 * big) return 1;
alpar@1
  2108
      /* create transformation stack entry */
alpar@1
  2109
      info = npp_push_tse(npp,
alpar@1
  2110
         rcv_forcing_row, sizeof(struct forcing_row));
alpar@1
  2111
      info->p = p->i;
alpar@1
  2112
      if (p->lb == p->ub)
alpar@1
  2113
      {  /* equality constraint */
alpar@1
  2114
         info->stat = GLP_NS;
alpar@1
  2115
      }
alpar@1
  2116
      else if (at == 0)
alpar@1
  2117
      {  /* inequality constraint; case L[p] = U'[p] */
alpar@1
  2118
         info->stat = GLP_NL;
alpar@1
  2119
         xassert(p->lb != -DBL_MAX);
alpar@1
  2120
      }
alpar@1
  2121
      else /* at == 1 */
alpar@1
  2122
      {  /* inequality constraint; case U[p] = L'[p] */
alpar@1
  2123
         info->stat = GLP_NU;
alpar@1
  2124
         xassert(p->ub != +DBL_MAX);
alpar@1
  2125
      }
alpar@1
  2126
      info->ptr = NULL;
alpar@1
  2127
      /* scan the forcing row, fix columns at corresponding bounds, and
alpar@1
  2128
         save column information (the latter is not needed for MIP) */
alpar@1
  2129
      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2130
      {  /* column j has non-zero coefficient in the forcing row */
alpar@1
  2131
         j = apj->col;
alpar@1
  2132
         /* it must be non-fixed */
alpar@1
  2133
         xassert(j->lb < j->ub);
alpar@1
  2134
         /* allocate stack entry to save column information */
alpar@1
  2135
         if (npp->sol != GLP_MIP)
alpar@1
  2136
         {  col = dmp_get_atom(npp->stack, sizeof(struct forcing_col));
alpar@1
  2137
            col->j = j->j;
alpar@1
  2138
            col->stat = -1; /* will be set below */
alpar@1
  2139
            col->a = apj->val;
alpar@1
  2140
            col->c = j->coef;
alpar@1
  2141
            col->ptr = NULL;
alpar@1
  2142
            col->next = info->ptr;
alpar@1
  2143
            info->ptr = col;
alpar@1
  2144
         }
alpar@1
  2145
         /* fix column j */
alpar@1
  2146
         if (at == 0 && apj->val < 0.0 || at != 0 && apj->val > 0.0)
alpar@1
  2147
         {  /* at its lower bound */
alpar@1
  2148
            if (npp->sol != GLP_MIP)
alpar@1
  2149
               col->stat = GLP_NL;
alpar@1
  2150
            xassert(j->lb != -DBL_MAX);
alpar@1
  2151
            j->ub = j->lb;
alpar@1
  2152
         }
alpar@1
  2153
         else
alpar@1
  2154
         {  /* at its upper bound */
alpar@1
  2155
            if (npp->sol != GLP_MIP)
alpar@1
  2156
               col->stat = GLP_NU;
alpar@1
  2157
            xassert(j->ub != +DBL_MAX);
alpar@1
  2158
            j->lb = j->ub;
alpar@1
  2159
         }
alpar@1
  2160
         /* save column coefficients a[i,j], i != p */
alpar@1
  2161
         if (npp->sol != GLP_MIP)
alpar@1
  2162
         {  for (aij = j->ptr; aij != NULL; aij = aij->c_next)
alpar@1
  2163
            {  if (aij == apj) continue; /* skip a[p,j] */
alpar@1
  2164
               lfe = dmp_get_atom(npp->stack, sizeof(NPPLFE));
alpar@1
  2165
               lfe->ref = aij->row->i;
alpar@1
  2166
               lfe->val = aij->val;
alpar@1
  2167
               lfe->next = col->ptr;
alpar@1
  2168
               col->ptr = lfe;
alpar@1
  2169
            }
alpar@1
  2170
         }
alpar@1
  2171
      }
alpar@1
  2172
      /* make the row free (unbounded) */
alpar@1
  2173
      p->lb = -DBL_MAX, p->ub = +DBL_MAX;
alpar@1
  2174
      return 0;
alpar@1
  2175
}
alpar@1
  2176
alpar@1
  2177
static int rcv_forcing_row(NPP *npp, void *_info)
alpar@1
  2178
{     /* recover forcing row */
alpar@1
  2179
      struct forcing_row *info = _info;
alpar@1
  2180
      struct forcing_col *col, *piv;
alpar@1
  2181
      NPPLFE *lfe;
alpar@1
  2182
      double d, big, temp;
alpar@1
  2183
      if (npp->sol == GLP_MIP) goto done;
alpar@1
  2184
      /* initially solution to the original problem is the same as
alpar@1
  2185
         to the transformed problem, where row p is inactive constraint
alpar@1
  2186
         with pi[p] = 0, and all columns are non-basic */
alpar@1
  2187
      if (npp->sol == GLP_SOL)
alpar@1
  2188
      {  if (npp->r_stat[info->p] != GLP_BS)
alpar@1
  2189
         {  npp_error();
alpar@1
  2190
            return 1;
alpar@1
  2191
         }
alpar@1
  2192
         for (col = info->ptr; col != NULL; col = col->next)
alpar@1
  2193
         {  if (npp->c_stat[col->j] != GLP_NS)
alpar@1
  2194
            {  npp_error();
alpar@1
  2195
               return 1;
alpar@1
  2196
            }
alpar@1
  2197
            npp->c_stat[col->j] = col->stat; /* original status */
alpar@1
  2198
         }
alpar@1
  2199
      }
alpar@1
  2200
      /* compute reduced costs d[j] for all columns with formula (10)
alpar@1
  2201
         and store them in col.c instead objective coefficients */
alpar@1
  2202
      for (col = info->ptr; col != NULL; col = col->next)
alpar@1
  2203
      {  d = col->c;
alpar@1
  2204
         for (lfe = col->ptr; lfe != NULL; lfe = lfe->next)
alpar@1
  2205
            d -= lfe->val * npp->r_pi[lfe->ref];
alpar@1
  2206
         col->c = d;
alpar@1
  2207
      }
alpar@1
  2208
      /* consider columns j, whose multipliers lambda[j] has wrong
alpar@1
  2209
         sign in solution to the transformed problem (where lambda[j] =
alpar@1
  2210
         d[j]), and choose column q, whose multipler lambda[q] reaches
alpar@1
  2211
         zero last on changing row multiplier pi[p]; see (14) */
alpar@1
  2212
      piv = NULL, big = 0.0;
alpar@1
  2213
      for (col = info->ptr; col != NULL; col = col->next)
alpar@1
  2214
      {  d = col->c; /* d[j] */
alpar@1
  2215
         temp = fabs(d / col->a);
alpar@1
  2216
         if (col->stat == GLP_NL)
alpar@1
  2217
         {  /* column j has active lower bound */
alpar@1
  2218
            if (d < 0.0 && big < temp)
alpar@1
  2219
               piv = col, big = temp;
alpar@1
  2220
         }
alpar@1
  2221
         else if (col->stat == GLP_NU)
alpar@1
  2222
         {  /* column j has active upper bound */
alpar@1
  2223
            if (d > 0.0 && big < temp)
alpar@1
  2224
               piv = col, big = temp;
alpar@1
  2225
         }
alpar@1
  2226
         else
alpar@1
  2227
         {  npp_error();
alpar@1
  2228
            return 1;
alpar@1
  2229
         }
alpar@1
  2230
      }
alpar@1
  2231
      /* if column q does not exist, no correction is needed */
alpar@1
  2232
      if (piv != NULL)
alpar@1
  2233
      {  /* correct solution; row p becomes active constraint while
alpar@1
  2234
            column q becomes basic */
alpar@1
  2235
         if (npp->sol == GLP_SOL)
alpar@1
  2236
         {  npp->r_stat[info->p] = info->stat;
alpar@1
  2237
            npp->c_stat[piv->j] = GLP_BS;
alpar@1
  2238
         }
alpar@1
  2239
         /* assign new value to row multiplier pi[p] = d[p] / a[p,q] */
alpar@1
  2240
         npp->r_pi[info->p] = piv->c / piv->a;
alpar@1
  2241
      }
alpar@1
  2242
done: return 0;
alpar@1
  2243
}
alpar@1
  2244
alpar@1
  2245
/***********************************************************************
alpar@1
  2246
*  NAME
alpar@1
  2247
*
alpar@1
  2248
*  npp_analyze_row - perform general row analysis
alpar@1
  2249
*
alpar@1
  2250
*  SYNOPSIS
alpar@1
  2251
*
alpar@1
  2252
*  #include "glpnpp.h"
alpar@1
  2253
*  int npp_analyze_row(NPP *npp, NPPROW *p);
alpar@1
  2254
*
alpar@1
  2255
*  DESCRIPTION
alpar@1
  2256
*
alpar@1
  2257
*  The routine npp_analyze_row performs analysis of row p of general
alpar@1
  2258
*  format:
alpar@1
  2259
*
alpar@1
  2260
*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
alpar@1
  2261
*              j
alpar@1
  2262
*
alpar@1
  2263
*     l[j] <= x[j] <= u[j],                                          (2)
alpar@1
  2264
*
alpar@1
  2265
*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0.
alpar@1
  2266
*
alpar@1
  2267
*  RETURNS
alpar@1
  2268
*
alpar@1
  2269
*  0x?0 - row lower bound does not exist or is redundant;
alpar@1
  2270
*
alpar@1
  2271
*  0x?1 - row lower bound can be active;
alpar@1
  2272
*
alpar@1
  2273
*  0x?2 - row lower bound is a forcing bound;
alpar@1
  2274
*
alpar@1
  2275
*  0x0? - row upper bound does not exist or is redundant;
alpar@1
  2276
*
alpar@1
  2277
*  0x1? - row upper bound can be active;
alpar@1
  2278
*
alpar@1
  2279
*  0x2? - row upper bound is a forcing bound;
alpar@1
  2280
*
alpar@1
  2281
*  0x33 - row bounds are inconsistent with column bounds.
alpar@1
  2282
*
alpar@1
  2283
*  ALGORITHM
alpar@1
  2284
*
alpar@1
  2285
*  Analysis of row (1) is based on analysis of its implied lower and
alpar@1
  2286
*  upper bounds, which are determined by bounds of corresponding columns
alpar@1
  2287
*  (variables) as follows:
alpar@1
  2288
*
alpar@1
  2289
*     L'[p] = inf sum a[p,j] x[j] =
alpar@1
  2290
*                  j
alpar@1
  2291
*                                                                    (3)
alpar@1
  2292
*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
alpar@1
  2293
*            j in Jp             j in Jn
alpar@1
  2294
*
alpar@1
  2295
*     U'[p] = sup sum a[p,j] x[j] =
alpar@1
  2296
*                                                                    (4)
alpar@1
  2297
*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
alpar@1
  2298
*            j in Jp             j in Jn
alpar@1
  2299
*
alpar@1
  2300
*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
alpar@1
  2301
*
alpar@1
  2302
*  (Note that bounds of all columns in row p are assumed to be correct,
alpar@1
  2303
*  so L'[p] <= U'[p].)
alpar@1
  2304
*
alpar@1
  2305
*  Analysis of row lower bound L[p] includes the following cases:
alpar@1
  2306
*
alpar@1
  2307
*  1) if L[p] > U'[p] + eps, where eps is an absolute tolerance for row
alpar@1
  2308
*     value, row lower bound L[p] and implied row upper bound U'[p] are
alpar@1
  2309
*     inconsistent, ergo, the problem has no primal feasible solution;
alpar@1
  2310
*
alpar@1
  2311
*  2) if U'[p] - eps <= L[p] <= U'[p] + eps, i.e. if L[p] =~ U'[p],
alpar@1
  2312
*     the row is a forcing row on its lower bound (see description of
alpar@1
  2313
*     the routine npp_forcing_row);
alpar@1
  2314
*
alpar@1
  2315
*  3) if L[p] > L'[p] + eps, row lower bound L[p] can be active (this
alpar@1
  2316
*     conclusion does not account other rows in the problem);
alpar@1
  2317
*
alpar@1
  2318
*  4) if L[p] <= L'[p] + eps, row lower bound L[p] cannot be active, so
alpar@1
  2319
*     it is redundant and can be removed (replaced by -oo).
alpar@1
  2320
*
alpar@1
  2321
*  Analysis of row upper bound U[p] is performed in a similar way and
alpar@1
  2322
*  includes the following cases:
alpar@1
  2323
*
alpar@1
  2324
*  1) if U[p] < L'[p] - eps, row upper bound U[p] and implied row lower
alpar@1
  2325
*     bound L'[p] are inconsistent, ergo the problem has no primal
alpar@1
  2326
*     feasible solution;
alpar@1
  2327
*
alpar@1
  2328
*  2) if L'[p] - eps <= U[p] <= L'[p] + eps, i.e. if U[p] =~ L'[p],
alpar@1
  2329
*     the row is a forcing row on its upper bound (see description of
alpar@1
  2330
*     the routine npp_forcing_row);
alpar@1
  2331
*
alpar@1
  2332
*  3) if U[p] < U'[p] - eps, row upper bound U[p] can be active (this
alpar@1
  2333
*     conclusion does not account other rows in the problem);
alpar@1
  2334
*
alpar@1
  2335
*  4) if U[p] >= U'[p] - eps, row upper bound U[p] cannot be active, so
alpar@1
  2336
*     it is redundant and can be removed (replaced by +oo). */
alpar@1
  2337
alpar@1
  2338
int npp_analyze_row(NPP *npp, NPPROW *p)
alpar@1
  2339
{     /* perform general row analysis */
alpar@1
  2340
      NPPAIJ *aij;
alpar@1
  2341
      int ret = 0x00;
alpar@1
  2342
      double l, u, eps;
alpar@1
  2343
      xassert(npp == npp);
alpar@1
  2344
      /* compute implied lower bound L'[p]; see (3) */
alpar@1
  2345
      l = 0.0;
alpar@1
  2346
      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  2347
      {  if (aij->val > 0.0)
alpar@1
  2348
         {  if (aij->col->lb == -DBL_MAX)
alpar@1
  2349
            {  l = -DBL_MAX;
alpar@1
  2350
               break;
alpar@1
  2351
            }
alpar@1
  2352
            l += aij->val * aij->col->lb;
alpar@1
  2353
         }
alpar@1
  2354
         else /* aij->val < 0.0 */
alpar@1
  2355
         {  if (aij->col->ub == +DBL_MAX)
alpar@1
  2356
            {  l = -DBL_MAX;
alpar@1
  2357
               break;
alpar@1
  2358
            }
alpar@1
  2359
            l += aij->val * aij->col->ub;
alpar@1
  2360
         }
alpar@1
  2361
      }
alpar@1
  2362
      /* compute implied upper bound U'[p]; see (4) */
alpar@1
  2363
      u = 0.0;
alpar@1
  2364
      for (aij = p->ptr; aij != NULL; aij = aij->r_next)
alpar@1
  2365
      {  if (aij->val > 0.0)
alpar@1
  2366
         {  if (aij->col->ub == +DBL_MAX)
alpar@1
  2367
            {  u = +DBL_MAX;
alpar@1
  2368
               break;
alpar@1
  2369
            }
alpar@1
  2370
            u += aij->val * aij->col->ub;
alpar@1
  2371
         }
alpar@1
  2372
         else /* aij->val < 0.0 */
alpar@1
  2373
         {  if (aij->col->lb == -DBL_MAX)
alpar@1
  2374
            {  u = +DBL_MAX;
alpar@1
  2375
               break;
alpar@1
  2376
            }
alpar@1
  2377
            u += aij->val * aij->col->lb;
alpar@1
  2378
         }
alpar@1
  2379
      }
alpar@1
  2380
      /* column bounds are assumed correct, so L'[p] <= U'[p] */
alpar@1
  2381
      /* check if row lower bound is consistent */
alpar@1
  2382
      if (p->lb != -DBL_MAX)
alpar@1
  2383
      {  eps = 1e-3 + 1e-6 * fabs(p->lb);
alpar@1
  2384
         if (p->lb - eps > u)
alpar@1
  2385
         {  ret = 0x33;
alpar@1
  2386
            goto done;
alpar@1
  2387
         }
alpar@1
  2388
      }
alpar@1
  2389
      /* check if row upper bound is consistent */
alpar@1
  2390
      if (p->ub != +DBL_MAX)
alpar@1
  2391
      {  eps = 1e-3 + 1e-6 * fabs(p->ub);
alpar@1
  2392
         if (p->ub + eps < l)
alpar@1
  2393
         {  ret = 0x33;
alpar@1
  2394
            goto done;
alpar@1
  2395
         }
alpar@1
  2396
      }
alpar@1
  2397
      /* check if row lower bound can be active/forcing */
alpar@1
  2398
      if (p->lb != -DBL_MAX)
alpar@1
  2399
      {  eps = 1e-9 + 1e-12 * fabs(p->lb);
alpar@1
  2400
         if (p->lb - eps > l)
alpar@1
  2401
         {  if (p->lb + eps <= u)
alpar@1
  2402
               ret |= 0x01;
alpar@1
  2403
            else
alpar@1
  2404
               ret |= 0x02;
alpar@1
  2405
         }
alpar@1
  2406
      }
alpar@1
  2407
      /* check if row upper bound can be active/forcing */
alpar@1
  2408
      if (p->ub != +DBL_MAX)
alpar@1
  2409
      {  eps = 1e-9 + 1e-12 * fabs(p->ub);
alpar@1
  2410
         if (p->ub + eps < u)
alpar@1
  2411
         {  /* check if the upper bound is forcing */
alpar@1
  2412
            if (p->ub - eps >= l)
alpar@1
  2413
               ret |= 0x10;
alpar@1
  2414
            else
alpar@1
  2415
               ret |= 0x20;
alpar@1
  2416
         }
alpar@1
  2417
      }
alpar@1
  2418
done: return ret;
alpar@1
  2419
}
alpar@1
  2420
alpar@1
  2421
/***********************************************************************
alpar@1
  2422
*  NAME
alpar@1
  2423
*
alpar@1
  2424
*  npp_inactive_bound - remove row lower/upper inactive bound
alpar@1
  2425
*
alpar@1
  2426
*  SYNOPSIS
alpar@1
  2427
*
alpar@1
  2428
*  #include "glpnpp.h"
alpar@1
  2429
*  void npp_inactive_bound(NPP *npp, NPPROW *p, int which);
alpar@1
  2430
*
alpar@1
  2431
*  DESCRIPTION
alpar@1
  2432
*
alpar@1
  2433
*  The routine npp_inactive_bound removes lower (if which = 0) or upper
alpar@1
  2434
*  (if which = 1) bound of row p:
alpar@1
  2435
*
alpar@1
  2436
*     L[p] <= sum a[p,j] x[j] <= U[p],
alpar@1
  2437
*
alpar@1
  2438
*  which (bound) is assumed to be redundant.
alpar@1
  2439
*
alpar@1
  2440
*  PROBLEM TRANSFORMATION
alpar@1
  2441
*
alpar@1
  2442
*  If which = 0, current lower bound L[p] of row p is assigned -oo.
alpar@1
  2443
*  If which = 1, current upper bound U[p] of row p is assigned +oo.
alpar@1
  2444
*
alpar@1
  2445
*  RECOVERING BASIC SOLUTION
alpar@1
  2446
*
alpar@1
  2447
*  If in solution to the transformed problem row p is inactive
alpar@1
  2448
*  constraint (GLP_BS), its status is not changed in solution to the
alpar@1
  2449
*  original problem. Otherwise, status of row p in solution to the
alpar@1
  2450
*  original problem is defined by its type before transformation and
alpar@1
  2451
*  its status in solution to the transformed problem as follows:
alpar@1
  2452
*
alpar@1
  2453
*     +---------------------+-------+---------------+---------------+
alpar@1
  2454
*     |        Row          | Flag  | Row status in | Row status in |
alpar@1
  2455
*     |        type         | which | transfmd soln | original soln |
alpar@1
  2456
*     +---------------------+-------+---------------+---------------+
alpar@1
  2457
*     |     sum >= L[p]     |   0   |    GLP_NF     |    GLP_NL     |
alpar@1
  2458
*     |     sum <= U[p]     |   1   |    GLP_NF     |    GLP_NU     |
alpar@1
  2459
*     | L[p] <= sum <= U[p] |   0   |    GLP_NU     |    GLP_NU     |
alpar@1
  2460
*     | L[p] <= sum <= U[p] |   1   |    GLP_NL     |    GLP_NL     |
alpar@1
  2461
*     |  sum = L[p] = U[p]  |   0   |    GLP_NU     |    GLP_NS     |
alpar@1
  2462
*     |  sum = L[p] = U[p]  |   1   |    GLP_NL     |    GLP_NS     |
alpar@1
  2463
*     +---------------------+-------+---------------+---------------+
alpar@1
  2464
*
alpar@1
  2465
*  RECOVERING INTERIOR-POINT SOLUTION
alpar@1
  2466
*
alpar@1
  2467
*  None needed.
alpar@1
  2468
*
alpar@1
  2469
*  RECOVERING MIP SOLUTION
alpar@1
  2470
*
alpar@1
  2471
*  None needed. */
alpar@1
  2472
alpar@1
  2473
struct inactive_bound
alpar@1
  2474
{     /* row inactive bound */
alpar@1
  2475
      int p;
alpar@1
  2476
      /* row reference number */
alpar@1
  2477
      char stat;
alpar@1
  2478
      /* row status (if active constraint) */
alpar@1
  2479
};
alpar@1
  2480
alpar@1
  2481
static int rcv_inactive_bound(NPP *npp, void *info);
alpar@1
  2482
alpar@1
  2483
void npp_inactive_bound(NPP *npp, NPPROW *p, int which)
alpar@1
  2484
{     /* remove row lower/upper inactive bound */
alpar@1
  2485
      struct inactive_bound *info;
alpar@1
  2486
      if (npp->sol == GLP_SOL)
alpar@1
  2487
      {  /* create transformation stack entry */
alpar@1
  2488
         info = npp_push_tse(npp,
alpar@1
  2489
            rcv_inactive_bound, sizeof(struct inactive_bound));
alpar@1
  2490
         info->p = p->i;
alpar@1
  2491
         if (p->ub == +DBL_MAX)
alpar@1
  2492
            info->stat = GLP_NL;
alpar@1
  2493
         else if (p->lb == -DBL_MAX)
alpar@1
  2494
            info->stat = GLP_NU;
alpar@1
  2495
         else if (p->lb != p->ub)
alpar@1
  2496
            info->stat = (char)(which == 0 ? GLP_NU : GLP_NL);
alpar@1
  2497
         else
alpar@1
  2498
            info->stat = GLP_NS;
alpar@1
  2499
      }
alpar@1
  2500
      /* remove row inactive bound */
alpar@1
  2501
      if (which == 0)
alpar@1
  2502
      {  xassert(p->lb != -DBL_MAX);
alpar@1
  2503
         p->lb = -DBL_MAX;
alpar@1
  2504
      }
alpar@1
  2505
      else if (which == 1)
alpar@1
  2506
      {  xassert(p->ub != +DBL_MAX);
alpar@1
  2507
         p->ub = +DBL_MAX;
alpar@1
  2508
      }
alpar@1
  2509
      else
alpar@1
  2510
         xassert(which != which);
alpar@1
  2511
      return;
alpar@1
  2512
}
alpar@1
  2513
alpar@1
  2514
static int rcv_inactive_bound(NPP *npp, void *_info)
alpar@1
  2515
{     /* recover row status */
alpar@1
  2516
      struct inactive_bound *info = _info;
alpar@1
  2517
      if (npp->sol != GLP_SOL)
alpar@1
  2518
      {  npp_error();
alpar@1
  2519
         return 1;
alpar@1
  2520
      }
alpar@1
  2521
      if (npp->r_stat[info->p] == GLP_BS)
alpar@1
  2522
         npp->r_stat[info->p] = GLP_BS;
alpar@1
  2523
      else
alpar@1
  2524
         npp->r_stat[info->p] = info->stat;
alpar@1
  2525
      return 0;
alpar@1
  2526
}
alpar@1
  2527
alpar@1
  2528
/***********************************************************************
alpar@1
  2529
*  NAME
alpar@1
  2530
*
alpar@1
  2531
*  npp_implied_bounds - determine implied column bounds
alpar@1
  2532
*
alpar@1
  2533
*  SYNOPSIS
alpar@1
  2534
*
alpar@1
  2535
*  #include "glpnpp.h"
alpar@1
  2536
*  void npp_implied_bounds(NPP *npp, NPPROW *p);
alpar@1
  2537
*
alpar@1
  2538
*  DESCRIPTION
alpar@1
  2539
*
alpar@1
  2540
*  The routine npp_implied_bounds inspects general row (constraint) p:
alpar@1
  2541
*
alpar@1
  2542
*     L[p] <= sum a[p,j] x[j] <= U[p],                               (1)
alpar@1
  2543
*
alpar@1
  2544
*     l[j] <= x[j] <= u[j],                                          (2)
alpar@1
  2545
*
alpar@1
  2546
*  where L[p] <= U[p] and l[j] <= u[j] for all a[p,j] != 0, to compute
alpar@1
  2547
*  implied bounds of columns (variables x[j]) in this row.
alpar@1
  2548
*
alpar@1
  2549
*  The routine stores implied column bounds l'[j] and u'[j] in column
alpar@1
  2550
*  descriptors (NPPCOL); it does not change current column bounds l[j]
alpar@1
  2551
*  and u[j]. (Implied column bounds can be then used to strengthen the
alpar@1
  2552
*  current column bounds; see the routines npp_implied_lower and
alpar@1
  2553
*  npp_implied_upper).
alpar@1
  2554
*
alpar@1
  2555
*  ALGORITHM
alpar@1
  2556
*
alpar@1
  2557
*  Current column bounds (2) define implied lower and upper bounds of
alpar@1
  2558
*  row (1) as follows:
alpar@1
  2559
*
alpar@1
  2560
*     L'[p] = inf sum a[p,j] x[j] =
alpar@1
  2561
*                  j
alpar@1
  2562
*                                                                    (3)
alpar@1
  2563
*           =  sum  a[p,j] l[j] +  sum  a[p,j] u[j],
alpar@1
  2564
*            j in Jp             j in Jn
alpar@1
  2565
*
alpar@1
  2566
*     U'[p] = sup sum a[p,j] x[j] =
alpar@1
  2567
*                                                                    (4)
alpar@1
  2568
*           =  sum  a[p,j] u[j] +  sum  a[p,j] l[j],
alpar@1
  2569
*            j in Jp             j in Jn
alpar@1
  2570
*
alpar@1
  2571
*     Jp = {j: a[p,j] > 0},  Jn = {j: a[p,j] < 0}.                   (5)
alpar@1
  2572
*
alpar@1
  2573
*  (Note that bounds of all columns in row p are assumed to be correct,
alpar@1
  2574
*  so L'[p] <= U'[p].)
alpar@1
  2575
*
alpar@1
  2576
*  If L[p] > L'[p] and/or U[p] < U'[p], the lower and/or upper bound of
alpar@1
  2577
*  row (1) can be active, in which case such row defines implied bounds
alpar@1
  2578
*  of its variables.
alpar@1
  2579
*
alpar@1
  2580
*  Let x[k] be some variable having in row (1) coefficient a[p,k] != 0.
alpar@1
  2581
*  Consider a case when row lower bound can be active (L[p] > L'[p]):
alpar@1
  2582
*
alpar@1
  2583
*     sum a[p,j] x[j] >= L[p]  ==>
alpar@1
  2584
*      j
alpar@1
  2585
*
alpar@1
  2586
*     sum a[p,j] x[j] + a[p,k] x[k] >= L[p]  ==>
alpar@1
  2587
*     j!=k
alpar@1
  2588
*                                                                    (6)
alpar@1
  2589
*     a[p,k] x[k] >= L[p] - sum a[p,j] x[j]  ==>
alpar@1
  2590
*                           j!=k
alpar@1
  2591
*
alpar@1
  2592
*     a[p,k] x[k] >= L[p,k],
alpar@1
  2593
*
alpar@1
  2594
*  where
alpar@1
  2595
*
alpar@1
  2596
*     L[p,k] = inf(L[p] - sum a[p,j] x[j]) =
alpar@1
  2597
*                         j!=k
alpar@1
  2598
*
alpar@1
  2599
*            = L[p] - sup sum a[p,j] x[j] =                          (7)
alpar@1
  2600
*                         j!=k
alpar@1
  2601
*
alpar@1
  2602
*            = L[p] - sum a[p,j] u[j] - sum a[p,j] l[j].
alpar@1
  2603
*                    j in Jp\{k}       j in Jn\{k}
alpar@1
  2604
*
alpar@1
  2605
*  Thus:
alpar@1
  2606
*
alpar@1
  2607
*     x[k] >= l'[k] = L[p,k] / a[p,k],  if a[p,k] > 0,               (8)
alpar@1
  2608
*
alpar@1
  2609
*     x[k] <= u'[k] = L[p,k] / a[p,k],  if a[p,k] < 0.               (9)
alpar@1
  2610
*
alpar@1
  2611
*  where l'[k] and u'[k] are implied lower and upper bounds of variable
alpar@1
  2612
*  x[k], resp.
alpar@1
  2613
*
alpar@1
  2614
*  Now consider a similar case when row upper bound can be active
alpar@1
  2615
*  (U[p] < U'[p]):
alpar@1
  2616
*
alpar@1
  2617
*     sum a[p,j] x[j] <= U[p]  ==>
alpar@1
  2618
*      j
alpar@1
  2619
*
alpar@1
  2620
*     sum a[p,j] x[j] + a[p,k] x[k] <= U[p]  ==>
alpar@1
  2621
*     j!=k
alpar@1
  2622
*                                                                   (10)
alpar@1
  2623
*     a[p,k] x[k] <= U[p] - sum a[p,j] x[j]  ==>
alpar@1
  2624
*                           j!=k
alpar@1
  2625
*
alpar@1
  2626
*     a[p,k] x[k] <= U[p,k],
alpar@1
  2627
*
alpar@1
  2628
*  where:
alpar@1
  2629
*
alpar@1
  2630
*     U[p,k] = sup(U[p] - sum a[p,j] x[j]) =
alpar@1
  2631
*                         j!=k
alpar@1
  2632
*
alpar@1
  2633
*            = U[p] - inf sum a[p,j] x[j] =                         (11)
alpar@1
  2634
*                         j!=k
alpar@1
  2635
*
alpar@1
  2636
*            = U[p] - sum a[p,j] l[j] - sum a[p,j] u[j].
alpar@1
  2637
*                    j in Jp\{k}       j in Jn\{k}
alpar@1
  2638
*
alpar@1
  2639
*  Thus:
alpar@1
  2640
*
alpar@1
  2641
*     x[k] <= u'[k] = U[p,k] / a[p,k],  if a[p,k] > 0,              (12)
alpar@1
  2642
*
alpar@1
  2643
*     x[k] >= l'[k] = U[p,k] / a[p,k],  if a[p,k] < 0.              (13)
alpar@1
  2644
*
alpar@1
  2645
*  Note that in formulae (8), (9), (12), and (13) coefficient a[p,k]
alpar@1
  2646
*  must not be too small in magnitude relatively to other non-zero
alpar@1
  2647
*  coefficients in row (1), i.e. the following condition must hold:
alpar@1
  2648
*
alpar@1
  2649
*     |a[p,k]| >= eps * max(1, |a[p,j]|),                           (14)
alpar@1
  2650
*                        j
alpar@1
  2651
*
alpar@1
  2652
*  where eps is a relative tolerance for constraint coefficients.
alpar@1
  2653
*  Otherwise the implied column bounds can be numerical inreliable. For
alpar@1
  2654
*  example, using formula (8) for the following inequality constraint:
alpar@1
  2655
*
alpar@1
  2656
*     1e-12 x1 - x2 - x3 >= 0,
alpar@1
  2657
*
alpar@1
  2658
*  where x1 >= -1, x2, x3, >= 0, may lead to numerically unreliable
alpar@1
  2659
*  conclusion that x1 >= 0.
alpar@1
  2660
*
alpar@1
  2661
*  Using formulae (8), (9), (12), and (13) to compute implied bounds
alpar@1
  2662
*  for one variable requires |J| operations, where J = {j: a[p,j] != 0},
alpar@1
  2663
*  because this needs computing L[p,k] and U[p,k]. Thus, computing
alpar@1
  2664
*  implied bounds for all variables in row (1) would require |J|^2
alpar@1
  2665
*  operations, that is not a good technique. However, the total number
alpar@1
  2666
*  of operations can be reduced to |J| as follows.
alpar@1
  2667
*
alpar@1
  2668
*  Let a[p,k] > 0. Then from (7) and (11) we have:
alpar@1
  2669
*
alpar@1
  2670
*     L[p,k] = L[p] - (U'[p] - a[p,k] u[k]) =
alpar@1
  2671
*
alpar@1
  2672
*            = L[p] - U'[p] + a[p,k] u[k],
alpar@1
  2673
*
alpar@1
  2674
*     U[p,k] = U[p] - (L'[p] - a[p,k] l[k]) =
alpar@1
  2675
*
alpar@1
  2676
*            = U[p] - L'[p] + a[p,k] l[k],
alpar@1
  2677
*
alpar@1
  2678
*  where L'[p] and U'[p] are implied row lower and upper bounds defined
alpar@1
  2679
*  by formulae (3) and (4). Substituting these expressions into (8) and
alpar@1
  2680
*  (12) gives:
alpar@1
  2681
*
alpar@1
  2682
*     l'[k] = L[p,k] / a[p,k] = u[k] + (L[p] - U'[p]) / a[p,k],     (15)
alpar@1
  2683
*
alpar@1
  2684
*     u'[k] = U[p,k] / a[p,k] = l[k] + (U[p] - L'[p]) / a[p,k].     (16)
alpar@1
  2685
*
alpar@1
  2686
*  Similarly, if a[p,k] < 0, according to (7) and (11) we have:
alpar@1
  2687
*
alpar@1
  2688
*     L[p,k] = L[p] - (U'[p] - a[p,k] l[k]) =
alpar@1
  2689
*
alpar@1
  2690
*            = L[p] - U'[p] + a[p,k] l[k],
alpar@1
  2691
*
alpar@1
  2692
*     U[p,k] = U[p] - (L'[p] - a[p,k] u[k]) =
alpar@1
  2693
*
alpar@1
  2694
*            = U[p] - L'[p] + a[p,k] u[k],
alpar@1
  2695
*
alpar@1
  2696
*  and substituting these expressions into (8) and (12) gives:
alpar@1
  2697
*
alpar@1
  2698
*     l'[k] = U[p,k] / a[p,k] = u[k] + (U[p] - L'[p]) / a[p,k],     (17)
alpar@1
  2699
*
alpar@1
  2700
*     u'[k] = L[p,k] / a[p,k] = l[k] + (L[p] - U'[p]) / a[p,k].     (18)
alpar@1
  2701
*
alpar@1
  2702
*  Note that formulae (15)-(18) can be used only if L'[p] and U'[p]
alpar@1
  2703
*  exist. However, if for some variable x[j] it happens that l[j] = -oo
alpar@1
  2704
*  and/or u[j] = +oo, values of L'[p] (if a[p,j] > 0) and/or U'[p] (if
alpar@1
  2705
*  a[p,j] < 0) are undefined. Consider, therefore, the most general
alpar@1
  2706
*  situation, when some column bounds (2) may not exist.
alpar@1
  2707
*
alpar@1
  2708
*  Let:
alpar@1
  2709
*
alpar@1
  2710
*     J' = {j : (a[p,j] > 0 and l[j] = -oo) or
alpar@1
  2711
*                                                                   (19)
alpar@1
  2712
*               (a[p,j] < 0 and u[j] = +oo)}.
alpar@1
  2713
*
alpar@1
  2714
*  Then (assuming that row upper bound U[p] can be active) the following
alpar@1
  2715
*  three cases are possible:
alpar@1
  2716
*
alpar@1
  2717
*  1) |J'| = 0. In this case L'[p] exists, thus, for all variables x[j]
alpar@1
  2718
*     in row (1) we can use formulae (16) and (17);
alpar@1
  2719
*
alpar@1
  2720
*  2) J' = {k}. In this case L'[p] = -oo, however, U[p,k] (11) exists,
alpar@1
  2721
*     so for variable x[k] we can use formulae (12) and (13). Note that
alpar@1
  2722
*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] < 0)
alpar@1
  2723
*     or u'[j] = +oo (if a[p,j] > 0);
alpar@1
  2724
*
alpar@1
  2725
*  3) |J'| > 1. In this case for all variables x[j] in row [1] we have
alpar@1
  2726
*     l'[j] = -oo (if a[p,j] < 0) or u'[j] = +oo (if a[p,j] > 0).
alpar@1
  2727
*
alpar@1
  2728
*  Similarly, let:
alpar@1
  2729
*
alpar@1
  2730
*     J'' = {j : (a[p,j] > 0 and u[j] = +oo) or
alpar@1
  2731
*                                                                   (20)
alpar@1
  2732
*                (a[p,j] < 0 and l[j] = -oo)}.
alpar@1
  2733
*
alpar@1
  2734
*  Then (assuming that row lower bound L[p] can be active) the following
alpar@1
  2735
*  three cases are possible:
alpar@1
  2736
*
alpar@1
  2737
*  1) |J''| = 0. In this case U'[p] exists, thus, for all variables x[j]
alpar@1
  2738
*     in row (1) we can use formulae (15) and (18);
alpar@1
  2739
*
alpar@1
  2740
*  2) J'' = {k}. In this case U'[p] = +oo, however, L[p,k] (7) exists,
alpar@1
  2741
*     so for variable x[k] we can use formulae (8) and (9). Note that
alpar@1
  2742
*     for all other variables x[j] (j != k) l'[j] = -oo (if a[p,j] > 0)
alpar@1
  2743
*     or u'[j] = +oo (if a[p,j] < 0);
alpar@1
  2744
*
alpar@1
  2745
*  3) |J''| > 1. In this case for all variables x[j] in row (1) we have
alpar@1
  2746
*     l'[j] = -oo (if a[p,j] > 0) or u'[j] = +oo (if a[p,j] < 0). */
alpar@1
  2747
alpar@1
  2748
void npp_implied_bounds(NPP *npp, NPPROW *p)
alpar@1
  2749
{     NPPAIJ *apj, *apk;
alpar@1
  2750
      double big, eps, temp;
alpar@1
  2751
      xassert(npp == npp);
alpar@1
  2752
      /* initialize implied bounds for all variables and determine
alpar@1
  2753
         maximal magnitude of row coefficients a[p,j] */
alpar@1
  2754
      big = 1.0;
alpar@1
  2755
      for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2756
      {  apj->col->ll.ll = -DBL_MAX, apj->col->uu.uu = +DBL_MAX;
alpar@1
  2757
         if (big < fabs(apj->val)) big = fabs(apj->val);
alpar@1
  2758
      }
alpar@1
  2759
      eps = 1e-6 * big;
alpar@1
  2760
      /* process row lower bound (assuming that it can be active) */
alpar@1
  2761
      if (p->lb != -DBL_MAX)
alpar@1
  2762
      {  apk = NULL;
alpar@1
  2763
         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2764
         {  if (apj->val > 0.0 && apj->col->ub == +DBL_MAX ||
alpar@1
  2765
                apj->val < 0.0 && apj->col->lb == -DBL_MAX)
alpar@1
  2766
            {  if (apk == NULL)
alpar@1
  2767
                  apk = apj;
alpar@1
  2768
               else
alpar@1
  2769
                  goto skip1;
alpar@1
  2770
            }
alpar@1
  2771
         }
alpar@1
  2772
         /* if a[p,k] = NULL then |J'| = 0 else J' = { k } */
alpar@1
  2773
         temp = p->lb;
alpar@1
  2774
         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2775
         {  if (apj == apk)
alpar@1
  2776
               /* skip a[p,k] */;
alpar@1
  2777
            else if (apj->val > 0.0)
alpar@1
  2778
               temp -= apj->val * apj->col->ub;
alpar@1
  2779
            else /* apj->val < 0.0 */
alpar@1
  2780
               temp -= apj->val * apj->col->lb;
alpar@1
  2781
         }
alpar@1
  2782
         /* compute column implied bounds */
alpar@1
  2783
         if (apk == NULL)
alpar@1
  2784
         {  /* temp = L[p] - U'[p] */
alpar@1
  2785
            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2786
            {  if (apj->val >= +eps)
alpar@1
  2787
               {  /* l'[j] := u[j] + (L[p] - U'[p]) / a[p,j] */
alpar@1
  2788
                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
alpar@1
  2789
               }
alpar@1
  2790
               else if (apj->val <= -eps)
alpar@1
  2791
               {  /* u'[j] := l[j] + (L[p] - U'[p]) / a[p,j] */
alpar@1
  2792
                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
alpar@1
  2793
               }
alpar@1
  2794
            }
alpar@1
  2795
         }
alpar@1
  2796
         else
alpar@1
  2797
         {  /* temp = L[p,k] */
alpar@1
  2798
            if (apk->val >= +eps)
alpar@1
  2799
            {  /* l'[k] := L[p,k] / a[p,k] */
alpar@1
  2800
               apk->col->ll.ll = temp / apk->val;
alpar@1
  2801
            }
alpar@1
  2802
            else if (apk->val <= -eps)
alpar@1
  2803
            {  /* u'[k] := L[p,k] / a[p,k] */
alpar@1
  2804
               apk->col->uu.uu = temp / apk->val;
alpar@1
  2805
            }
alpar@1
  2806
         }
alpar@1
  2807
skip1:   ;
alpar@1
  2808
      }
alpar@1
  2809
      /* process row upper bound (assuming that it can be active) */
alpar@1
  2810
      if (p->ub != +DBL_MAX)
alpar@1
  2811
      {  apk = NULL;
alpar@1
  2812
         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2813
         {  if (apj->val > 0.0 && apj->col->lb == -DBL_MAX ||
alpar@1
  2814
                apj->val < 0.0 && apj->col->ub == +DBL_MAX)
alpar@1
  2815
            {  if (apk == NULL)
alpar@1
  2816
                  apk = apj;
alpar@1
  2817
               else
alpar@1
  2818
                  goto skip2;
alpar@1
  2819
            }
alpar@1
  2820
         }
alpar@1
  2821
         /* if a[p,k] = NULL then |J''| = 0 else J'' = { k } */
alpar@1
  2822
         temp = p->ub;
alpar@1
  2823
         for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2824
         {  if (apj == apk)
alpar@1
  2825
               /* skip a[p,k] */;
alpar@1
  2826
            else if (apj->val > 0.0)
alpar@1
  2827
               temp -= apj->val * apj->col->lb;
alpar@1
  2828
            else /* apj->val < 0.0 */
alpar@1
  2829
               temp -= apj->val * apj->col->ub;
alpar@1
  2830
         }
alpar@1
  2831
         /* compute column implied bounds */
alpar@1
  2832
         if (apk == NULL)
alpar@1
  2833
         {  /* temp = U[p] - L'[p] */
alpar@1
  2834
            for (apj = p->ptr; apj != NULL; apj = apj->r_next)
alpar@1
  2835
            {  if (apj->val >= +eps)
alpar@1
  2836
               {  /* u'[j] := l[j] + (U[p] - L'[p]) / a[p,j] */
alpar@1
  2837
                  apj->col->uu.uu = apj->col->lb + temp / apj->val;
alpar@1
  2838
               }
alpar@1
  2839
               else if (apj->val <= -eps)
alpar@1
  2840
               {  /* l'[j] := u[j] + (U[p] - L'[p]) / a[p,j] */
alpar@1
  2841
                  apj->col->ll.ll = apj->col->ub + temp / apj->val;
alpar@1
  2842
               }
alpar@1
  2843
            }
alpar@1
  2844
         }
alpar@1
  2845
         else
alpar@1
  2846
         {  /* temp = U[p,k] */
alpar@1
  2847
            if (apk->val >= +eps)
alpar@1
  2848
            {  /* u'[k] := U[p,k] / a[p,k] */
alpar@1
  2849
               apk->col->uu.uu = temp / apk->val;
alpar@1
  2850
            }
alpar@1
  2851
            else if (apk->val <= -eps)
alpar@1
  2852
            {  /* l'[k] := U[p,k] / a[p,k] */
alpar@1
  2853
               apk->col->ll.ll = temp / apk->val;
alpar@1
  2854
            }
alpar@1
  2855
         }
alpar@1
  2856
skip2:   ;
alpar@1
  2857
      }
alpar@1
  2858
      return;
alpar@1
  2859
}
alpar@1
  2860
alpar@1
  2861
/* eof */