src/glpnpp05.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
/* glpnpp05.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_clean_prob - perform initial LP/MIP processing
alpar@1
    31
*
alpar@1
    32
*  SYNOPSIS
alpar@1
    33
*
alpar@1
    34
*  #include "glpnpp.h"
alpar@1
    35
*  void npp_clean_prob(NPP *npp);
alpar@1
    36
*
alpar@1
    37
*  DESCRIPTION
alpar@1
    38
*
alpar@1
    39
*  The routine npp_clean_prob performs initial LP/MIP processing that
alpar@1
    40
*  currently includes:
alpar@1
    41
*
alpar@1
    42
*  1) removing free rows;
alpar@1
    43
*
alpar@1
    44
*  2) replacing double-sided constraint rows with almost identical
alpar@1
    45
*     bounds, by equality constraint rows;
alpar@1
    46
*
alpar@1
    47
*  3) removing fixed columns;
alpar@1
    48
*
alpar@1
    49
*  4) replacing double-bounded columns with almost identical bounds by
alpar@1
    50
*     fixed columns and removing those columns;
alpar@1
    51
*
alpar@1
    52
*  5) initial processing constraint coefficients (not implemented);
alpar@1
    53
*
alpar@1
    54
*  6) initial processing objective coefficients (not implemented). */
alpar@1
    55
alpar@1
    56
void npp_clean_prob(NPP *npp)
alpar@1
    57
{     /* perform initial LP/MIP processing */
alpar@1
    58
      NPPROW *row, *next_row;
alpar@1
    59
      NPPCOL *col, *next_col;
alpar@1
    60
      int ret;
alpar@1
    61
      xassert(npp == npp);
alpar@1
    62
      /* process rows which originally are free */
alpar@1
    63
      for (row = npp->r_head; row != NULL; row = next_row)
alpar@1
    64
      {  next_row = row->next;
alpar@1
    65
         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
alpar@1
    66
         {  /* process free row */
alpar@1
    67
#ifdef GLP_DEBUG
alpar@1
    68
            xprintf("1");
alpar@1
    69
#endif
alpar@1
    70
            npp_free_row(npp, row);
alpar@1
    71
            /* row was deleted */
alpar@1
    72
         }
alpar@1
    73
      }
alpar@1
    74
      /* process rows which originally are double-sided inequalities */
alpar@1
    75
      for (row = npp->r_head; row != NULL; row = next_row)
alpar@1
    76
      {  next_row = row->next;
alpar@1
    77
         if (row->lb != -DBL_MAX && row->ub != +DBL_MAX &&
alpar@1
    78
             row->lb < row->ub)
alpar@1
    79
         {  ret = npp_make_equality(npp, row);
alpar@1
    80
            if (ret == 0)
alpar@1
    81
               ;
alpar@1
    82
            else if (ret == 1)
alpar@1
    83
            {  /* row was replaced by equality constraint */
alpar@1
    84
#ifdef GLP_DEBUG
alpar@1
    85
               xprintf("2");
alpar@1
    86
#endif
alpar@1
    87
            }
alpar@1
    88
            else
alpar@1
    89
               xassert(ret != ret);
alpar@1
    90
         }
alpar@1
    91
      }
alpar@1
    92
      /* process columns which are originally fixed */
alpar@1
    93
      for (col = npp->c_head; col != NULL; col = next_col)
alpar@1
    94
      {  next_col = col->next;
alpar@1
    95
         if (col->lb == col->ub)
alpar@1
    96
         {  /* process fixed column */
alpar@1
    97
#ifdef GLP_DEBUG
alpar@1
    98
            xprintf("3");
alpar@1
    99
#endif
alpar@1
   100
            npp_fixed_col(npp, col);
alpar@1
   101
            /* column was deleted */
alpar@1
   102
         }
alpar@1
   103
      }
alpar@1
   104
      /* process columns which are originally double-bounded */
alpar@1
   105
      for (col = npp->c_head; col != NULL; col = next_col)
alpar@1
   106
      {  next_col = col->next;
alpar@1
   107
         if (col->lb != -DBL_MAX && col->ub != +DBL_MAX &&
alpar@1
   108
             col->lb < col->ub)
alpar@1
   109
         {  ret = npp_make_fixed(npp, col);
alpar@1
   110
            if (ret == 0)
alpar@1
   111
               ;
alpar@1
   112
            else if (ret == 1)
alpar@1
   113
            {  /* column was replaced by fixed column; process it */
alpar@1
   114
#ifdef GLP_DEBUG
alpar@1
   115
               xprintf("4");
alpar@1
   116
#endif
alpar@1
   117
               npp_fixed_col(npp, col);
alpar@1
   118
               /* column was deleted */
alpar@1
   119
            }
alpar@1
   120
         }
alpar@1
   121
      }
alpar@1
   122
      return;
alpar@1
   123
}
alpar@1
   124
alpar@1
   125
/***********************************************************************
alpar@1
   126
*  NAME
alpar@1
   127
*
alpar@1
   128
*  npp_process_row - perform basic row processing
alpar@1
   129
*
alpar@1
   130
*  SYNOPSIS
alpar@1
   131
*
alpar@1
   132
*  #include "glpnpp.h"
alpar@1
   133
*  int npp_process_row(NPP *npp, NPPROW *row, int hard);
alpar@1
   134
*
alpar@1
   135
*  DESCRIPTION
alpar@1
   136
*
alpar@1
   137
*  The routine npp_process_row performs basic row processing that
alpar@1
   138
*  currently includes:
alpar@1
   139
*
alpar@1
   140
*  1) removing empty row;
alpar@1
   141
*
alpar@1
   142
*  2) removing equality constraint row singleton and corresponding
alpar@1
   143
*     column;
alpar@1
   144
*
alpar@1
   145
*  3) removing inequality constraint row singleton and corresponding
alpar@1
   146
*     column if it was fixed;
alpar@1
   147
*
alpar@1
   148
*  4) performing general row analysis;
alpar@1
   149
*
alpar@1
   150
*  5) removing redundant row bounds;
alpar@1
   151
*
alpar@1
   152
*  6) removing forcing row and corresponding columns;
alpar@1
   153
*
alpar@1
   154
*  7) removing row which becomes free due to redundant bounds;
alpar@1
   155
*
alpar@1
   156
*  8) computing implied bounds for all columns in the row and using
alpar@1
   157
*     them to strengthen current column bounds (MIP only, optional,
alpar@1
   158
*     performed if the flag hard is on).
alpar@1
   159
*
alpar@1
   160
*  Additionally the routine may activate affected rows and/or columns
alpar@1
   161
*  for further processing.
alpar@1
   162
*
alpar@1
   163
*  RETURNS
alpar@1
   164
*
alpar@1
   165
*  0           success;
alpar@1
   166
*
alpar@1
   167
*  GLP_ENOPFS  primal/integer infeasibility detected;
alpar@1
   168
*
alpar@1
   169
*  GLP_ENODFS  dual infeasibility detected. */
alpar@1
   170
alpar@1
   171
int npp_process_row(NPP *npp, NPPROW *row, int hard)
alpar@1
   172
{     /* perform basic row processing */
alpar@1
   173
      NPPCOL *col;
alpar@1
   174
      NPPAIJ *aij, *next_aij, *aaa;
alpar@1
   175
      int ret;
alpar@1
   176
      /* row must not be free */
alpar@1
   177
      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
alpar@1
   178
      /* start processing row */
alpar@1
   179
      if (row->ptr == NULL)
alpar@1
   180
      {  /* empty row */
alpar@1
   181
         ret = npp_empty_row(npp, row);
alpar@1
   182
         if (ret == 0)
alpar@1
   183
         {  /* row was deleted */
alpar@1
   184
#ifdef GLP_DEBUG
alpar@1
   185
            xprintf("A");
alpar@1
   186
#endif
alpar@1
   187
            return 0;
alpar@1
   188
         }
alpar@1
   189
         else if (ret == 1)
alpar@1
   190
         {  /* primal infeasibility */
alpar@1
   191
            return GLP_ENOPFS;
alpar@1
   192
         }
alpar@1
   193
         else
alpar@1
   194
            xassert(ret != ret);
alpar@1
   195
      }
alpar@1
   196
      if (row->ptr->r_next == NULL)
alpar@1
   197
      {  /* row singleton */
alpar@1
   198
         col = row->ptr->col;
alpar@1
   199
         if (row->lb == row->ub)
alpar@1
   200
         {  /* equality constraint */
alpar@1
   201
            ret = npp_eq_singlet(npp, row);
alpar@1
   202
            if (ret == 0)
alpar@1
   203
            {  /* column was fixed, row was deleted */
alpar@1
   204
#ifdef GLP_DEBUG
alpar@1
   205
               xprintf("B");
alpar@1
   206
#endif
alpar@1
   207
               /* activate rows affected by column */
alpar@1
   208
               for (aij = col->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   209
                  npp_activate_row(npp, aij->row);
alpar@1
   210
               /* process fixed column */
alpar@1
   211
               npp_fixed_col(npp, col);
alpar@1
   212
               /* column was deleted */
alpar@1
   213
               return 0;
alpar@1
   214
            }
alpar@1
   215
            else if (ret == 1 || ret == 2)
alpar@1
   216
            {  /* primal/integer infeasibility */
alpar@1
   217
               return GLP_ENOPFS;
alpar@1
   218
            }
alpar@1
   219
            else
alpar@1
   220
               xassert(ret != ret);
alpar@1
   221
         }
alpar@1
   222
         else
alpar@1
   223
         {  /* inequality constraint */
alpar@1
   224
            ret = npp_ineq_singlet(npp, row);
alpar@1
   225
            if (0 <= ret && ret <= 3)
alpar@1
   226
            {  /* row was deleted */
alpar@1
   227
#ifdef GLP_DEBUG
alpar@1
   228
               xprintf("C");
alpar@1
   229
#endif
alpar@1
   230
               /* activate column, since its length was changed due to
alpar@1
   231
                  row deletion */
alpar@1
   232
               npp_activate_col(npp, col);
alpar@1
   233
               if (ret >= 2)
alpar@1
   234
               {  /* column bounds changed significantly or column was
alpar@1
   235
                     fixed */
alpar@1
   236
                  /* activate rows affected by column */
alpar@1
   237
                  for (aij = col->ptr; aij != NULL; aij = aij->c_next)
alpar@1
   238
                     npp_activate_row(npp, aij->row);
alpar@1
   239
               }
alpar@1
   240
               if (ret == 3)
alpar@1
   241
               {  /* column was fixed; process it */
alpar@1
   242
#ifdef GLP_DEBUG
alpar@1
   243
                  xprintf("D");
alpar@1
   244
#endif
alpar@1
   245
                  npp_fixed_col(npp, col);
alpar@1
   246
                  /* column was deleted */
alpar@1
   247
               }
alpar@1
   248
               return 0;
alpar@1
   249
            }
alpar@1
   250
            else if (ret == 4)
alpar@1
   251
            {  /* primal infeasibility */
alpar@1
   252
               return GLP_ENOPFS;
alpar@1
   253
            }
alpar@1
   254
            else
alpar@1
   255
               xassert(ret != ret);
alpar@1
   256
         }
alpar@1
   257
      }
alpar@1
   258
#if 0
alpar@1
   259
      /* sometimes this causes too large round-off errors; probably
alpar@1
   260
         pivot coefficient should be chosen more carefully */
alpar@1
   261
      if (row->ptr->r_next->r_next == NULL)
alpar@1
   262
      {  /* row doubleton */
alpar@1
   263
         if (row->lb == row->ub)
alpar@1
   264
         {  /* equality constraint */
alpar@1
   265
            if (!(row->ptr->col->is_int ||
alpar@1
   266
                  row->ptr->r_next->col->is_int))
alpar@1
   267
            {  /* both columns are continuous */
alpar@1
   268
               NPPCOL *q;
alpar@1
   269
               q = npp_eq_doublet(npp, row);
alpar@1
   270
               if (q != NULL)
alpar@1
   271
               {  /* column q was eliminated */
alpar@1
   272
#ifdef GLP_DEBUG
alpar@1
   273
                  xprintf("E");
alpar@1
   274
#endif
alpar@1
   275
                  /* now column q is singleton of type "implied slack
alpar@1
   276
                     variable"; we process it here to make sure that on
alpar@1
   277
                     recovering basic solution the row is always active
alpar@1
   278
                     equality constraint (as required by the routine
alpar@1
   279
                     rcv_eq_doublet) */
alpar@1
   280
                  xassert(npp_process_col(npp, q) == 0);
alpar@1
   281
                  /* column q was deleted; note that row p also may be
alpar@1
   282
                     deleted */
alpar@1
   283
                  return 0;
alpar@1
   284
               }
alpar@1
   285
            }
alpar@1
   286
         }
alpar@1
   287
      }
alpar@1
   288
#endif
alpar@1
   289
      /* general row analysis */
alpar@1
   290
      ret = npp_analyze_row(npp, row);
alpar@1
   291
      xassert(0x00 <= ret && ret <= 0xFF);
alpar@1
   292
      if (ret == 0x33)
alpar@1
   293
      {  /* row bounds are inconsistent with column bounds */
alpar@1
   294
         return GLP_ENOPFS;
alpar@1
   295
      }
alpar@1
   296
      if ((ret & 0x0F) == 0x00)
alpar@1
   297
      {  /* row lower bound does not exist or redundant */
alpar@1
   298
         if (row->lb != -DBL_MAX)
alpar@1
   299
         {  /* remove redundant row lower bound */
alpar@1
   300
#ifdef GLP_DEBUG
alpar@1
   301
            xprintf("F");
alpar@1
   302
#endif
alpar@1
   303
            npp_inactive_bound(npp, row, 0);
alpar@1
   304
         }
alpar@1
   305
      }
alpar@1
   306
      else if ((ret & 0x0F) == 0x01)
alpar@1
   307
      {  /* row lower bound can be active */
alpar@1
   308
         /* see below */
alpar@1
   309
      }
alpar@1
   310
      else if ((ret & 0x0F) == 0x02)
alpar@1
   311
      {  /* row lower bound is a forcing bound */
alpar@1
   312
#ifdef GLP_DEBUG
alpar@1
   313
         xprintf("G");
alpar@1
   314
#endif
alpar@1
   315
         /* process forcing row */
alpar@1
   316
         if (npp_forcing_row(npp, row, 0) == 0)
alpar@1
   317
fixup:   {  /* columns were fixed, row was made free */
alpar@1
   318
            for (aij = row->ptr; aij != NULL; aij = next_aij)
alpar@1
   319
            {  /* process column fixed by forcing row */
alpar@1
   320
#ifdef GLP_DEBUG
alpar@1
   321
               xprintf("H");
alpar@1
   322
#endif
alpar@1
   323
               col = aij->col;
alpar@1
   324
               next_aij = aij->r_next;
alpar@1
   325
               /* activate rows affected by column */
alpar@1
   326
               for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
alpar@1
   327
                  npp_activate_row(npp, aaa->row);
alpar@1
   328
               /* process fixed column */
alpar@1
   329
               npp_fixed_col(npp, col);
alpar@1
   330
               /* column was deleted */
alpar@1
   331
            }
alpar@1
   332
            /* process free row (which now is empty due to deletion of
alpar@1
   333
               all its columns) */
alpar@1
   334
            npp_free_row(npp, row);
alpar@1
   335
            /* row was deleted */
alpar@1
   336
            return 0;
alpar@1
   337
         }
alpar@1
   338
      }
alpar@1
   339
      else
alpar@1
   340
         xassert(ret != ret);
alpar@1
   341
      if ((ret & 0xF0) == 0x00)
alpar@1
   342
      {  /* row upper bound does not exist or redundant */
alpar@1
   343
         if (row->ub != +DBL_MAX)
alpar@1
   344
         {  /* remove redundant row upper bound */
alpar@1
   345
#ifdef GLP_DEBUG
alpar@1
   346
            xprintf("I");
alpar@1
   347
#endif
alpar@1
   348
            npp_inactive_bound(npp, row, 1);
alpar@1
   349
         }
alpar@1
   350
      }
alpar@1
   351
      else if ((ret & 0xF0) == 0x10)
alpar@1
   352
      {  /* row upper bound can be active */
alpar@1
   353
         /* see below */
alpar@1
   354
      }
alpar@1
   355
      else if ((ret & 0xF0) == 0x20)
alpar@1
   356
      {  /* row upper bound is a forcing bound */
alpar@1
   357
#ifdef GLP_DEBUG
alpar@1
   358
         xprintf("J");
alpar@1
   359
#endif
alpar@1
   360
         /* process forcing row */
alpar@1
   361
         if (npp_forcing_row(npp, row, 1) == 0) goto fixup;
alpar@1
   362
      }
alpar@1
   363
      else
alpar@1
   364
         xassert(ret != ret);
alpar@1
   365
      if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
alpar@1
   366
      {  /* row became free due to redundant bounds removal */
alpar@1
   367
#ifdef GLP_DEBUG
alpar@1
   368
         xprintf("K");
alpar@1
   369
#endif
alpar@1
   370
         /* activate its columns, since their length will change due
alpar@1
   371
            to row deletion */
alpar@1
   372
         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
alpar@1
   373
            npp_activate_col(npp, aij->col);
alpar@1
   374
         /* process free row */
alpar@1
   375
         npp_free_row(npp, row);
alpar@1
   376
         /* row was deleted */
alpar@1
   377
         return 0;
alpar@1
   378
      }
alpar@1
   379
#if 1 /* 23/XII-2009 */
alpar@1
   380
      /* row lower and/or upper bounds can be active */
alpar@1
   381
      if (npp->sol == GLP_MIP && hard)
alpar@1
   382
      {  /* improve current column bounds (optional) */
alpar@1
   383
         if (npp_improve_bounds(npp, row, 1) < 0)
alpar@1
   384
            return GLP_ENOPFS;
alpar@1
   385
      }
alpar@1
   386
#endif
alpar@1
   387
      return 0;
alpar@1
   388
}
alpar@1
   389
alpar@1
   390
/***********************************************************************
alpar@1
   391
*  NAME
alpar@1
   392
*
alpar@1
   393
*  npp_improve_bounds - improve current column bounds
alpar@1
   394
*
alpar@1
   395
*  SYNOPSIS
alpar@1
   396
*
alpar@1
   397
*  #include "glpnpp.h"
alpar@1
   398
*  int npp_improve_bounds(NPP *npp, NPPROW *row, int flag);
alpar@1
   399
*
alpar@1
   400
*  DESCRIPTION
alpar@1
   401
*
alpar@1
   402
*  The routine npp_improve_bounds analyzes specified row (inequality
alpar@1
   403
*  or equality constraint) to determine implied column bounds and then
alpar@1
   404
*  uses these bounds to improve (strengthen) current column bounds.
alpar@1
   405
*
alpar@1
   406
*  If the flag is on and current column bounds changed significantly
alpar@1
   407
*  or the column was fixed, the routine activate rows affected by the
alpar@1
   408
*  column for further processing. (This feature is intended to be used
alpar@1
   409
*  in the main loop of the routine npp_process_row.)
alpar@1
   410
*
alpar@1
   411
*  NOTE: This operation can be used for MIP problem only.
alpar@1
   412
*
alpar@1
   413
*  RETURNS
alpar@1
   414
*
alpar@1
   415
*  The routine npp_improve_bounds returns the number of significantly
alpar@1
   416
*  changed bounds plus the number of column having been fixed due to
alpar@1
   417
*  bound improvements. However, if the routine detects primal/integer
alpar@1
   418
*  infeasibility, it returns a negative value. */
alpar@1
   419
alpar@1
   420
int npp_improve_bounds(NPP *npp, NPPROW *row, int flag)
alpar@1
   421
{     /* improve current column bounds */
alpar@1
   422
      NPPCOL *col;
alpar@1
   423
      NPPAIJ *aij, *next_aij, *aaa;
alpar@1
   424
      int kase, ret, count = 0;
alpar@1
   425
      double lb, ub;
alpar@1
   426
      xassert(npp->sol == GLP_MIP);
alpar@1
   427
      /* row must not be free */
alpar@1
   428
      xassert(!(row->lb == -DBL_MAX && row->ub == +DBL_MAX));
alpar@1
   429
      /* determine implied column bounds */
alpar@1
   430
      npp_implied_bounds(npp, row);
alpar@1
   431
      /* and use these bounds to strengthen current column bounds */
alpar@1
   432
      for (aij = row->ptr; aij != NULL; aij = next_aij)
alpar@1
   433
      {  col = aij->col;
alpar@1
   434
         next_aij = aij->r_next;
alpar@1
   435
         for (kase = 0; kase <= 1; kase++)
alpar@1
   436
         {  /* save current column bounds */
alpar@1
   437
            lb = col->lb, ub = col->ub;
alpar@1
   438
            if (kase == 0)
alpar@1
   439
            {  /* process implied column lower bound */
alpar@1
   440
               if (col->ll.ll == -DBL_MAX) continue;
alpar@1
   441
               ret = npp_implied_lower(npp, col, col->ll.ll);
alpar@1
   442
            }
alpar@1
   443
            else
alpar@1
   444
            {  /* process implied column upper bound */
alpar@1
   445
               if (col->uu.uu == +DBL_MAX) continue;
alpar@1
   446
               ret = npp_implied_upper(npp, col, col->uu.uu);
alpar@1
   447
            }
alpar@1
   448
            if (ret == 0 || ret == 1)
alpar@1
   449
            {  /* current column bounds did not change or changed, but
alpar@1
   450
                  not significantly; restore current column bounds */
alpar@1
   451
               col->lb = lb, col->ub = ub;
alpar@1
   452
            }
alpar@1
   453
            else if (ret == 2 || ret == 3)
alpar@1
   454
            {  /* current column bounds changed significantly or column
alpar@1
   455
                  was fixed */
alpar@1
   456
#ifdef GLP_DEBUG
alpar@1
   457
               xprintf("L");
alpar@1
   458
#endif
alpar@1
   459
               count++;
alpar@1
   460
               /* activate other rows affected by column, if required */
alpar@1
   461
               if (flag)
alpar@1
   462
               {  for (aaa = col->ptr; aaa != NULL; aaa = aaa->c_next)
alpar@1
   463
                  {  if (aaa->row != row)
alpar@1
   464
                        npp_activate_row(npp, aaa->row);
alpar@1
   465
                  }
alpar@1
   466
               }
alpar@1
   467
               if (ret == 3)
alpar@1
   468
               {  /* process fixed column */
alpar@1
   469
#ifdef GLP_DEBUG
alpar@1
   470
                  xprintf("M");
alpar@1
   471
#endif
alpar@1
   472
                  npp_fixed_col(npp, col);
alpar@1
   473
                  /* column was deleted */
alpar@1
   474
                  break; /* for kase */
alpar@1
   475
               }
alpar@1
   476
            }
alpar@1
   477
            else if (ret == 4)
alpar@1
   478
            {  /* primal/integer infeasibility */
alpar@1
   479
               return -1;
alpar@1
   480
            }
alpar@1
   481
            else
alpar@1
   482
               xassert(ret != ret);
alpar@1
   483
         }
alpar@1
   484
      }
alpar@1
   485
      return count;
alpar@1
   486
}
alpar@1
   487
alpar@1
   488
/***********************************************************************
alpar@1
   489
*  NAME
alpar@1
   490
*
alpar@1
   491
*  npp_process_col - perform basic column processing
alpar@1
   492
*
alpar@1
   493
*  SYNOPSIS
alpar@1
   494
*
alpar@1
   495
*  #include "glpnpp.h"
alpar@1
   496
*  int npp_process_col(NPP *npp, NPPCOL *col);
alpar@1
   497
*
alpar@1
   498
*  DESCRIPTION
alpar@1
   499
*
alpar@1
   500
*  The routine npp_process_col performs basic column processing that
alpar@1
   501
*  currently includes:
alpar@1
   502
*
alpar@1
   503
*  1) fixing and removing empty column;
alpar@1
   504
*
alpar@1
   505
*  2) removing column singleton, which is implied slack variable, and
alpar@1
   506
*     corresponding row if it becomes free;
alpar@1
   507
*
alpar@1
   508
*  3) removing bounds of column, which is implied free variable, and
alpar@1
   509
*     replacing corresponding row by equality constraint.
alpar@1
   510
*
alpar@1
   511
*  Additionally the routine may activate affected rows and/or columns
alpar@1
   512
*  for further processing.
alpar@1
   513
*
alpar@1
   514
*  RETURNS
alpar@1
   515
*
alpar@1
   516
*  0           success;
alpar@1
   517
*
alpar@1
   518
*  GLP_ENOPFS  primal/integer infeasibility detected;
alpar@1
   519
*
alpar@1
   520
*  GLP_ENODFS  dual infeasibility detected. */
alpar@1
   521
alpar@1
   522
int npp_process_col(NPP *npp, NPPCOL *col)
alpar@1
   523
{     /* perform basic column processing */
alpar@1
   524
      NPPROW *row;
alpar@1
   525
      NPPAIJ *aij;
alpar@1
   526
      int ret;
alpar@1
   527
      /* column must not be fixed */
alpar@1
   528
      xassert(col->lb < col->ub);
alpar@1
   529
      /* start processing column */
alpar@1
   530
      if (col->ptr == NULL)
alpar@1
   531
      {  /* empty column */
alpar@1
   532
         ret = npp_empty_col(npp, col);
alpar@1
   533
         if (ret == 0)
alpar@1
   534
         {  /* column was fixed and deleted */
alpar@1
   535
#ifdef GLP_DEBUG
alpar@1
   536
            xprintf("N");
alpar@1
   537
#endif
alpar@1
   538
            return 0;
alpar@1
   539
         }
alpar@1
   540
         else if (ret == 1)
alpar@1
   541
         {  /* dual infeasibility */
alpar@1
   542
            return GLP_ENODFS;
alpar@1
   543
         }
alpar@1
   544
         else
alpar@1
   545
            xassert(ret != ret);
alpar@1
   546
      }
alpar@1
   547
      if (col->ptr->c_next == NULL)
alpar@1
   548
      {  /* column singleton */
alpar@1
   549
         row = col->ptr->row;
alpar@1
   550
         if (row->lb == row->ub)
alpar@1
   551
         {  /* equality constraint */
alpar@1
   552
            if (!col->is_int)
alpar@1
   553
slack:      {  /* implied slack variable */
alpar@1
   554
#ifdef GLP_DEBUG
alpar@1
   555
               xprintf("O");
alpar@1
   556
#endif
alpar@1
   557
               npp_implied_slack(npp, col);
alpar@1
   558
               /* column was deleted */
alpar@1
   559
               if (row->lb == -DBL_MAX && row->ub == +DBL_MAX)
alpar@1
   560
               {  /* row became free due to implied slack variable */
alpar@1
   561
#ifdef GLP_DEBUG
alpar@1
   562
                  xprintf("P");
alpar@1
   563
#endif
alpar@1
   564
                  /* activate columns affected by row */
alpar@1
   565
                  for (aij = row->ptr; aij != NULL; aij = aij->r_next)
alpar@1
   566
                     npp_activate_col(npp, aij->col);
alpar@1
   567
                  /* process free row */
alpar@1
   568
                  npp_free_row(npp, row);
alpar@1
   569
                  /* row was deleted */
alpar@1
   570
               }
alpar@1
   571
               else
alpar@1
   572
               {  /* row became inequality constraint; activate it
alpar@1
   573
                     since its length changed due to column deletion */
alpar@1
   574
                  npp_activate_row(npp, row);
alpar@1
   575
               }
alpar@1
   576
               return 0;
alpar@1
   577
            }
alpar@1
   578
         }
alpar@1
   579
         else
alpar@1
   580
         {  /* inequality constraint */
alpar@1
   581
            if (!col->is_int)
alpar@1
   582
            {  ret = npp_implied_free(npp, col);
alpar@1
   583
               if (ret == 0)
alpar@1
   584
               {  /* implied free variable */
alpar@1
   585
#ifdef GLP_DEBUG
alpar@1
   586
                  xprintf("Q");
alpar@1
   587
#endif
alpar@1
   588
                  /* column bounds were removed, row was replaced by
alpar@1
   589
                     equality constraint */
alpar@1
   590
                  goto slack;
alpar@1
   591
               }
alpar@1
   592
               else if (ret == 1)
alpar@1
   593
               {  /* column is not implied free variable, because its
alpar@1
   594
                     lower and/or upper bounds can be active */
alpar@1
   595
               }
alpar@1
   596
               else if (ret == 2)
alpar@1
   597
               {  /* dual infeasibility */
alpar@1
   598
                  return GLP_ENODFS;
alpar@1
   599
               }
alpar@1
   600
            }
alpar@1
   601
         }
alpar@1
   602
      }
alpar@1
   603
      /* column still exists */
alpar@1
   604
      return 0;
alpar@1
   605
}
alpar@1
   606
alpar@1
   607
/***********************************************************************
alpar@1
   608
*  NAME
alpar@1
   609
*
alpar@1
   610
*  npp_process_prob - perform basic LP/MIP processing
alpar@1
   611
*
alpar@1
   612
*  SYNOPSIS
alpar@1
   613
*
alpar@1
   614
*  #include "glpnpp.h"
alpar@1
   615
*  int npp_process_prob(NPP *npp, int hard);
alpar@1
   616
*
alpar@1
   617
*  DESCRIPTION
alpar@1
   618
*
alpar@1
   619
*  The routine npp_process_prob performs basic LP/MIP processing that
alpar@1
   620
*  currently includes:
alpar@1
   621
*
alpar@1
   622
*  1) initial LP/MIP processing (see the routine npp_clean_prob),
alpar@1
   623
*
alpar@1
   624
*  2) basic row processing (see the routine npp_process_row), and
alpar@1
   625
*
alpar@1
   626
*  3) basic column processing (see the routine npp_process_col).
alpar@1
   627
*
alpar@1
   628
*  If the flag hard is on, the routine attempts to improve current
alpar@1
   629
*  column bounds multiple times within the main processing loop, in
alpar@1
   630
*  which case this feature may take a time. Otherwise, if the flag hard
alpar@1
   631
*  is off, improving column bounds is performed only once at the end of
alpar@1
   632
*  the main loop. (Note that this feature is used for MIP only.)
alpar@1
   633
*
alpar@1
   634
*  The routine uses two sets: the set of active rows and the set of
alpar@1
   635
*  active columns. Rows/columns are marked by a flag (the field temp in
alpar@1
   636
*  NPPROW/NPPCOL). If the flag is non-zero, the row/column is active,
alpar@1
   637
*  in which case it is placed in the beginning of the row/column list;
alpar@1
   638
*  otherwise, if the flag is zero, the row/column is inactive, in which
alpar@1
   639
*  case it is placed in the end of the row/column list. If a row/column
alpar@1
   640
*  being currently processed may affect other rows/columns, the latters
alpar@1
   641
*  are activated for further processing.
alpar@1
   642
*
alpar@1
   643
*  RETURNS
alpar@1
   644
*
alpar@1
   645
*  0           success;
alpar@1
   646
*
alpar@1
   647
*  GLP_ENOPFS  primal/integer infeasibility detected;
alpar@1
   648
*
alpar@1
   649
*  GLP_ENODFS  dual infeasibility detected. */
alpar@1
   650
alpar@1
   651
int npp_process_prob(NPP *npp, int hard)
alpar@1
   652
{     /* perform basic LP/MIP processing */
alpar@1
   653
      NPPROW *row;
alpar@1
   654
      NPPCOL *col;
alpar@1
   655
      int processing, ret;
alpar@1
   656
      /* perform initial LP/MIP processing */
alpar@1
   657
      npp_clean_prob(npp);
alpar@1
   658
      /* activate all remaining rows and columns */
alpar@1
   659
      for (row = npp->r_head; row != NULL; row = row->next)
alpar@1
   660
         row->temp = 1;
alpar@1
   661
      for (col = npp->c_head; col != NULL; col = col->next)
alpar@1
   662
         col->temp = 1;
alpar@1
   663
      /* main processing loop */
alpar@1
   664
      processing = 1;
alpar@1
   665
      while (processing)
alpar@1
   666
      {  processing = 0;
alpar@1
   667
         /* process all active rows */
alpar@1
   668
         for (;;)
alpar@1
   669
         {  row = npp->r_head;
alpar@1
   670
            if (row == NULL || !row->temp) break;
alpar@1
   671
            npp_deactivate_row(npp, row);
alpar@1
   672
            ret = npp_process_row(npp, row, hard);
alpar@1
   673
            if (ret != 0) goto done;
alpar@1
   674
            processing = 1;
alpar@1
   675
         }
alpar@1
   676
         /* process all active columns */
alpar@1
   677
         for (;;)
alpar@1
   678
         {  col = npp->c_head;
alpar@1
   679
            if (col == NULL || !col->temp) break;
alpar@1
   680
            npp_deactivate_col(npp, col);
alpar@1
   681
            ret = npp_process_col(npp, col);
alpar@1
   682
            if (ret != 0) goto done;
alpar@1
   683
            processing = 1;
alpar@1
   684
         }
alpar@1
   685
      }
alpar@1
   686
#if 1 /* 23/XII-2009 */
alpar@1
   687
      if (npp->sol == GLP_MIP && !hard)
alpar@1
   688
      {  /* improve current column bounds (optional) */
alpar@1
   689
         for (row = npp->r_head; row != NULL; row = row->next)
alpar@1
   690
         {  if (npp_improve_bounds(npp, row, 0) < 0)
alpar@1
   691
            {  ret = GLP_ENOPFS;
alpar@1
   692
               goto done;
alpar@1
   693
            }
alpar@1
   694
         }
alpar@1
   695
      }
alpar@1
   696
#endif
alpar@1
   697
      /* all seems ok */
alpar@1
   698
      ret = 0;
alpar@1
   699
done: xassert(ret == 0 || ret == GLP_ENOPFS || ret == GLP_ENODFS);
alpar@1
   700
#ifdef GLP_DEBUG
alpar@1
   701
      xprintf("\n");
alpar@1
   702
#endif
alpar@1
   703
      return ret;
alpar@1
   704
}
alpar@1
   705
alpar@1
   706
/**********************************************************************/
alpar@1
   707
alpar@1
   708
int npp_simplex(NPP *npp, const glp_smcp *parm)
alpar@1
   709
{     /* process LP prior to applying primal/dual simplex method */
alpar@1
   710
      int ret;
alpar@1
   711
      xassert(npp->sol == GLP_SOL);
alpar@1
   712
      xassert(parm == parm);
alpar@1
   713
      ret = npp_process_prob(npp, 0);
alpar@1
   714
      return ret;
alpar@1
   715
}
alpar@1
   716
alpar@1
   717
/**********************************************************************/
alpar@1
   718
alpar@1
   719
int npp_integer(NPP *npp, const glp_iocp *parm)
alpar@1
   720
{     /* process MIP prior to applying branch-and-bound method */
alpar@1
   721
      NPPROW *row, *prev_row;
alpar@1
   722
      NPPCOL *col;
alpar@1
   723
      NPPAIJ *aij;
alpar@1
   724
      int count, ret;
alpar@1
   725
      xassert(npp->sol == GLP_MIP);
alpar@1
   726
      xassert(parm == parm);
alpar@1
   727
      /*==============================================================*/
alpar@1
   728
      /* perform basic MIP processing */
alpar@1
   729
      ret = npp_process_prob(npp, 1);
alpar@1
   730
      if (ret != 0) goto done;
alpar@1
   731
      /*==============================================================*/
alpar@1
   732
      /* binarize problem, if required */
alpar@1
   733
      if (parm->binarize)
alpar@1
   734
         npp_binarize_prob(npp);
alpar@1
   735
      /*==============================================================*/
alpar@1
   736
      /* identify hidden packing inequalities */
alpar@1
   737
      count = 0;
alpar@1
   738
      /* new rows will be added to the end of the row list, so we go
alpar@1
   739
         from the end to beginning of the row list */
alpar@1
   740
      for (row = npp->r_tail; row != NULL; row = prev_row)
alpar@1
   741
      {  prev_row = row->prev;
alpar@1
   742
         /* skip free row */
alpar@1
   743
         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
alpar@1
   744
         /* skip equality constraint */
alpar@1
   745
         if (row->lb == row->ub) continue;
alpar@1
   746
         /* skip row having less than two variables */
alpar@1
   747
         if (row->ptr == NULL || row->ptr->r_next == NULL) continue;
alpar@1
   748
         /* skip row having non-binary variables */
alpar@1
   749
         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
alpar@1
   750
         {  col = aij->col;
alpar@1
   751
            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
alpar@1
   752
               break;
alpar@1
   753
         }
alpar@1
   754
         if (aij != NULL) continue;
alpar@1
   755
         count += npp_hidden_packing(npp, row);
alpar@1
   756
      }
alpar@1
   757
      if (count > 0)
alpar@1
   758
         xprintf("%d hidden packing inequaliti(es) were detected\n",
alpar@1
   759
            count);
alpar@1
   760
      /*==============================================================*/
alpar@1
   761
      /* identify hidden covering inequalities */
alpar@1
   762
      count = 0;
alpar@1
   763
      /* new rows will be added to the end of the row list, so we go
alpar@1
   764
         from the end to beginning of the row list */
alpar@1
   765
      for (row = npp->r_tail; row != NULL; row = prev_row)
alpar@1
   766
      {  prev_row = row->prev;
alpar@1
   767
         /* skip free row */
alpar@1
   768
         if (row->lb == -DBL_MAX && row->ub == +DBL_MAX) continue;
alpar@1
   769
         /* skip equality constraint */
alpar@1
   770
         if (row->lb == row->ub) continue;
alpar@1
   771
         /* skip row having less than three variables */
alpar@1
   772
         if (row->ptr == NULL || row->ptr->r_next == NULL ||
alpar@1
   773
             row->ptr->r_next->r_next == NULL) continue;
alpar@1
   774
         /* skip row having non-binary variables */
alpar@1
   775
         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
alpar@1
   776
         {  col = aij->col;
alpar@1
   777
            if (!(col->is_int && col->lb == 0.0 && col->ub == 1.0))
alpar@1
   778
               break;
alpar@1
   779
         }
alpar@1
   780
         if (aij != NULL) continue;
alpar@1
   781
         count += npp_hidden_covering(npp, row);
alpar@1
   782
      }
alpar@1
   783
      if (count > 0)
alpar@1
   784
         xprintf("%d hidden covering inequaliti(es) were detected\n",
alpar@1
   785
            count);
alpar@1
   786
      /*==============================================================*/
alpar@1
   787
      /* reduce inequality constraint coefficients */
alpar@1
   788
      count = 0;
alpar@1
   789
      /* new rows will be added to the end of the row list, so we go
alpar@1
   790
         from the end to beginning of the row list */
alpar@1
   791
      for (row = npp->r_tail; row != NULL; row = prev_row)
alpar@1
   792
      {  prev_row = row->prev;
alpar@1
   793
         /* skip equality constraint */
alpar@1
   794
         if (row->lb == row->ub) continue;
alpar@1
   795
         count += npp_reduce_ineq_coef(npp, row);
alpar@1
   796
      }
alpar@1
   797
      if (count > 0)
alpar@1
   798
         xprintf("%d constraint coefficient(s) were reduced\n", count);
alpar@1
   799
      /*==============================================================*/
alpar@1
   800
#ifdef GLP_DEBUG
alpar@1
   801
      routine(npp);
alpar@1
   802
#endif
alpar@1
   803
      /*==============================================================*/
alpar@1
   804
      /* all seems ok */
alpar@1
   805
      ret = 0;
alpar@1
   806
done: return ret;
alpar@1
   807
}
alpar@1
   808
alpar@1
   809
/* eof */