src/glplpf.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* glplpf.c (LP basis factorization, Schur complement version) */
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 "glplpf.h"
alpar@1
    26
#include "glpenv.h"
alpar@1
    27
#define xfault xerror
alpar@1
    28
alpar@1
    29
#define _GLPLPF_DEBUG 0
alpar@1
    30
alpar@1
    31
/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
alpar@1
    32
alpar@1
    33
#define M_MAX 100000000 /* = 100*10^6 */
alpar@1
    34
/* maximal order of the basis matrix */
alpar@1
    35
alpar@1
    36
/***********************************************************************
alpar@1
    37
*  NAME
alpar@1
    38
*
alpar@1
    39
*  lpf_create_it - create LP basis factorization
alpar@1
    40
*
alpar@1
    41
*  SYNOPSIS
alpar@1
    42
*
alpar@1
    43
*  #include "glplpf.h"
alpar@1
    44
*  LPF *lpf_create_it(void);
alpar@1
    45
*
alpar@1
    46
*  DESCRIPTION
alpar@1
    47
*
alpar@1
    48
*  The routine lpf_create_it creates a program object, which represents
alpar@1
    49
*  a factorization of LP basis.
alpar@1
    50
*
alpar@1
    51
*  RETURNS
alpar@1
    52
*
alpar@1
    53
*  The routine lpf_create_it returns a pointer to the object created. */
alpar@1
    54
alpar@1
    55
LPF *lpf_create_it(void)
alpar@1
    56
{     LPF *lpf;
alpar@1
    57
#if _GLPLPF_DEBUG
alpar@1
    58
      xprintf("lpf_create_it: warning: debug mode enabled\n");
alpar@1
    59
#endif
alpar@1
    60
      lpf = xmalloc(sizeof(LPF));
alpar@1
    61
      lpf->valid = 0;
alpar@1
    62
      lpf->m0_max = lpf->m0 = 0;
alpar@1
    63
      lpf->luf = luf_create_it();
alpar@1
    64
      lpf->m = 0;
alpar@1
    65
      lpf->B = NULL;
alpar@1
    66
      lpf->n_max = 50;
alpar@1
    67
      lpf->n = 0;
alpar@1
    68
      lpf->R_ptr = lpf->R_len = NULL;
alpar@1
    69
      lpf->S_ptr = lpf->S_len = NULL;
alpar@1
    70
      lpf->scf = NULL;
alpar@1
    71
      lpf->P_row = lpf->P_col = NULL;
alpar@1
    72
      lpf->Q_row = lpf->Q_col = NULL;
alpar@1
    73
      lpf->v_size = 1000;
alpar@1
    74
      lpf->v_ptr = 0;
alpar@1
    75
      lpf->v_ind = NULL;
alpar@1
    76
      lpf->v_val = NULL;
alpar@1
    77
      lpf->work1 = lpf->work2 = NULL;
alpar@1
    78
      return lpf;
alpar@1
    79
}
alpar@1
    80
alpar@1
    81
/***********************************************************************
alpar@1
    82
*  NAME
alpar@1
    83
*
alpar@1
    84
*  lpf_factorize - compute LP basis factorization
alpar@1
    85
*
alpar@1
    86
*  SYNOPSIS
alpar@1
    87
*
alpar@1
    88
*  #include "glplpf.h"
alpar@1
    89
*  int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
alpar@1
    90
*     (void *info, int j, int ind[], double val[]), void *info);
alpar@1
    91
*
alpar@1
    92
*  DESCRIPTION
alpar@1
    93
*
alpar@1
    94
*  The routine lpf_factorize computes the factorization of the basis
alpar@1
    95
*  matrix B specified by the routine col.
alpar@1
    96
*
alpar@1
    97
*  The parameter lpf specified the basis factorization data structure
alpar@1
    98
*  created with the routine lpf_create_it.
alpar@1
    99
*
alpar@1
   100
*  The parameter m specifies the order of B, m > 0.
alpar@1
   101
*
alpar@1
   102
*  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
alpar@1
   103
*  number of j-th column of B in some original matrix. The array bh is
alpar@1
   104
*  optional and can be specified as NULL.
alpar@1
   105
*
alpar@1
   106
*  The formal routine col specifies the matrix B to be factorized. To
alpar@1
   107
*  obtain j-th column of A the routine lpf_factorize calls the routine
alpar@1
   108
*  col with the parameter j (1 <= j <= n). In response the routine col
alpar@1
   109
*  should store row indices and numerical values of non-zero elements
alpar@1
   110
*  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
alpar@1
   111
*  respectively, where len is the number of non-zeros in j-th column
alpar@1
   112
*  returned on exit. Neither zero nor duplicate elements are allowed.
alpar@1
   113
*
alpar@1
   114
*  The parameter info is a transit pointer passed to the routine col.
alpar@1
   115
*
alpar@1
   116
*  RETURNS
alpar@1
   117
*
alpar@1
   118
*  0  The factorization has been successfully computed.
alpar@1
   119
*
alpar@1
   120
*  LPF_ESING
alpar@1
   121
*     The specified matrix is singular within the working precision.
alpar@1
   122
*
alpar@1
   123
*  LPF_ECOND
alpar@1
   124
*     The specified matrix is ill-conditioned.
alpar@1
   125
*
alpar@1
   126
*  For more details see comments to the routine luf_factorize. */
alpar@1
   127
alpar@1
   128
int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
alpar@1
   129
      (void *info, int j, int ind[], double val[]), void *info)
alpar@1
   130
{     int k, ret;
alpar@1
   131
#if _GLPLPF_DEBUG
alpar@1
   132
      int i, j, len, *ind;
alpar@1
   133
      double *B, *val;
alpar@1
   134
#endif
alpar@1
   135
      xassert(bh == bh);
alpar@1
   136
      if (m < 1)
alpar@1
   137
         xfault("lpf_factorize: m = %d; invalid parameter\n", m);
alpar@1
   138
      if (m > M_MAX)
alpar@1
   139
         xfault("lpf_factorize: m = %d; matrix too big\n", m);
alpar@1
   140
      lpf->m0 = lpf->m = m;
alpar@1
   141
      /* invalidate the factorization */
alpar@1
   142
      lpf->valid = 0;
alpar@1
   143
      /* allocate/reallocate arrays, if necessary */
alpar@1
   144
      if (lpf->R_ptr == NULL)
alpar@1
   145
         lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
alpar@1
   146
      if (lpf->R_len == NULL)
alpar@1
   147
         lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
alpar@1
   148
      if (lpf->S_ptr == NULL)
alpar@1
   149
         lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
alpar@1
   150
      if (lpf->S_len == NULL)
alpar@1
   151
         lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
alpar@1
   152
      if (lpf->scf == NULL)
alpar@1
   153
         lpf->scf = scf_create_it(lpf->n_max);
alpar@1
   154
      if (lpf->v_ind == NULL)
alpar@1
   155
         lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
alpar@1
   156
      if (lpf->v_val == NULL)
alpar@1
   157
         lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
alpar@1
   158
      if (lpf->m0_max < m)
alpar@1
   159
      {  if (lpf->P_row != NULL) xfree(lpf->P_row);
alpar@1
   160
         if (lpf->P_col != NULL) xfree(lpf->P_col);
alpar@1
   161
         if (lpf->Q_row != NULL) xfree(lpf->Q_row);
alpar@1
   162
         if (lpf->Q_col != NULL) xfree(lpf->Q_col);
alpar@1
   163
         if (lpf->work1 != NULL) xfree(lpf->work1);
alpar@1
   164
         if (lpf->work2 != NULL) xfree(lpf->work2);
alpar@1
   165
         lpf->m0_max = m + 100;
alpar@1
   166
         lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
alpar@1
   167
         lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
alpar@1
   168
         lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
alpar@1
   169
         lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
alpar@1
   170
         lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
alpar@1
   171
         lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
alpar@1
   172
      }
alpar@1
   173
      /* try to factorize the basis matrix */
alpar@1
   174
      switch (luf_factorize(lpf->luf, m, col, info))
alpar@1
   175
      {  case 0:
alpar@1
   176
            break;
alpar@1
   177
         case LUF_ESING:
alpar@1
   178
            ret = LPF_ESING;
alpar@1
   179
            goto done;
alpar@1
   180
         case LUF_ECOND:
alpar@1
   181
            ret = LPF_ECOND;
alpar@1
   182
            goto done;
alpar@1
   183
         default:
alpar@1
   184
            xassert(lpf != lpf);
alpar@1
   185
      }
alpar@1
   186
      /* the basis matrix has been successfully factorized */
alpar@1
   187
      lpf->valid = 1;
alpar@1
   188
#if _GLPLPF_DEBUG
alpar@1
   189
      /* store the basis matrix for debugging */
alpar@1
   190
      if (lpf->B != NULL) xfree(lpf->B);
alpar@1
   191
      xassert(m <= 32767);
alpar@1
   192
      lpf->B = B = xcalloc(1+m*m, sizeof(double));
alpar@1
   193
      ind = xcalloc(1+m, sizeof(int));
alpar@1
   194
      val = xcalloc(1+m, sizeof(double));
alpar@1
   195
      for (k = 1; k <= m * m; k++)
alpar@1
   196
         B[k] = 0.0;
alpar@1
   197
      for (j = 1; j <= m; j++)
alpar@1
   198
      {  len = col(info, j, ind, val);
alpar@1
   199
         xassert(0 <= len && len <= m);
alpar@1
   200
         for (k = 1; k <= len; k++)
alpar@1
   201
         {  i = ind[k];
alpar@1
   202
            xassert(1 <= i && i <= m);
alpar@1
   203
            xassert(B[(i - 1) * m + j] == 0.0);
alpar@1
   204
            xassert(val[k] != 0.0);
alpar@1
   205
            B[(i - 1) * m + j] = val[k];
alpar@1
   206
         }
alpar@1
   207
      }
alpar@1
   208
      xfree(ind);
alpar@1
   209
      xfree(val);
alpar@1
   210
#endif
alpar@1
   211
      /* B = B0, so there are no additional rows/columns */
alpar@1
   212
      lpf->n = 0;
alpar@1
   213
      /* reset the Schur complement factorization */
alpar@1
   214
      scf_reset_it(lpf->scf);
alpar@1
   215
      /* P := Q := I */
alpar@1
   216
      for (k = 1; k <= m; k++)
alpar@1
   217
      {  lpf->P_row[k] = lpf->P_col[k] = k;
alpar@1
   218
         lpf->Q_row[k] = lpf->Q_col[k] = k;
alpar@1
   219
      }
alpar@1
   220
      /* make all SVA locations free */
alpar@1
   221
      lpf->v_ptr = 1;
alpar@1
   222
      ret = 0;
alpar@1
   223
done: /* return to the calling program */
alpar@1
   224
      return ret;
alpar@1
   225
}
alpar@1
   226
alpar@1
   227
/***********************************************************************
alpar@1
   228
*  The routine r_prod computes the product y := y + alpha * R * x,
alpar@1
   229
*  where x is a n-vector, alpha is a scalar, y is a m0-vector.
alpar@1
   230
*
alpar@1
   231
*  Since matrix R is available by columns, the product is computed as
alpar@1
   232
*  a linear combination:
alpar@1
   233
*
alpar@1
   234
*     y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
alpar@1
   235
*
alpar@1
   236
*  where R[j] is j-th column of R. */
alpar@1
   237
alpar@1
   238
static void r_prod(LPF *lpf, double y[], double a, const double x[])
alpar@1
   239
{     int n = lpf->n;
alpar@1
   240
      int *R_ptr = lpf->R_ptr;
alpar@1
   241
      int *R_len = lpf->R_len;
alpar@1
   242
      int *v_ind = lpf->v_ind;
alpar@1
   243
      double *v_val = lpf->v_val;
alpar@1
   244
      int j, beg, end, ptr;
alpar@1
   245
      double t;
alpar@1
   246
      for (j = 1; j <= n; j++)
alpar@1
   247
      {  if (x[j] == 0.0) continue;
alpar@1
   248
         /* y := y + alpha * R[j] * x[j] */
alpar@1
   249
         t = a * x[j];
alpar@1
   250
         beg = R_ptr[j];
alpar@1
   251
         end = beg + R_len[j];
alpar@1
   252
         for (ptr = beg; ptr < end; ptr++)
alpar@1
   253
            y[v_ind[ptr]] += t * v_val[ptr];
alpar@1
   254
      }
alpar@1
   255
      return;
alpar@1
   256
}
alpar@1
   257
alpar@1
   258
/***********************************************************************
alpar@1
   259
*  The routine rt_prod computes the product y := y + alpha * R' * x,
alpar@1
   260
*  where R' is a matrix transposed to R, x is a m0-vector, alpha is a
alpar@1
   261
*  scalar, y is a n-vector.
alpar@1
   262
*
alpar@1
   263
*  Since matrix R is available by columns, the product components are
alpar@1
   264
*  computed as inner products:
alpar@1
   265
*
alpar@1
   266
*     y[j] := y[j] + alpha * (j-th column of R) * x
alpar@1
   267
*
alpar@1
   268
*  for j = 1, 2, ..., n. */
alpar@1
   269
alpar@1
   270
static void rt_prod(LPF *lpf, double y[], double a, const double x[])
alpar@1
   271
{     int n = lpf->n;
alpar@1
   272
      int *R_ptr = lpf->R_ptr;
alpar@1
   273
      int *R_len = lpf->R_len;
alpar@1
   274
      int *v_ind = lpf->v_ind;
alpar@1
   275
      double *v_val = lpf->v_val;
alpar@1
   276
      int j, beg, end, ptr;
alpar@1
   277
      double t;
alpar@1
   278
      for (j = 1; j <= n; j++)
alpar@1
   279
      {  /* t := (j-th column of R) * x */
alpar@1
   280
         t = 0.0;
alpar@1
   281
         beg = R_ptr[j];
alpar@1
   282
         end = beg + R_len[j];
alpar@1
   283
         for (ptr = beg; ptr < end; ptr++)
alpar@1
   284
            t += v_val[ptr] * x[v_ind[ptr]];
alpar@1
   285
         /* y[j] := y[j] + alpha * t */
alpar@1
   286
         y[j] += a * t;
alpar@1
   287
      }
alpar@1
   288
      return;
alpar@1
   289
}
alpar@1
   290
alpar@1
   291
/***********************************************************************
alpar@1
   292
*  The routine s_prod computes the product y := y + alpha * S * x,
alpar@1
   293
*  where x is a m0-vector, alpha is a scalar, y is a n-vector.
alpar@1
   294
*
alpar@1
   295
*  Since matrix S is available by rows, the product components are
alpar@1
   296
*  computed as inner products:
alpar@1
   297
*
alpar@1
   298
*     y[i] = y[i] + alpha * (i-th row of S) * x
alpar@1
   299
*
alpar@1
   300
*  for i = 1, 2, ..., n. */
alpar@1
   301
alpar@1
   302
static void s_prod(LPF *lpf, double y[], double a, const double x[])
alpar@1
   303
{     int n = lpf->n;
alpar@1
   304
      int *S_ptr = lpf->S_ptr;
alpar@1
   305
      int *S_len = lpf->S_len;
alpar@1
   306
      int *v_ind = lpf->v_ind;
alpar@1
   307
      double *v_val = lpf->v_val;
alpar@1
   308
      int i, beg, end, ptr;
alpar@1
   309
      double t;
alpar@1
   310
      for (i = 1; i <= n; i++)
alpar@1
   311
      {  /* t := (i-th row of S) * x */
alpar@1
   312
         t = 0.0;
alpar@1
   313
         beg = S_ptr[i];
alpar@1
   314
         end = beg + S_len[i];
alpar@1
   315
         for (ptr = beg; ptr < end; ptr++)
alpar@1
   316
            t += v_val[ptr] * x[v_ind[ptr]];
alpar@1
   317
         /* y[i] := y[i] + alpha * t */
alpar@1
   318
         y[i] += a * t;
alpar@1
   319
      }
alpar@1
   320
      return;
alpar@1
   321
}
alpar@1
   322
alpar@1
   323
/***********************************************************************
alpar@1
   324
*  The routine st_prod computes the product y := y + alpha * S' * x,
alpar@1
   325
*  where S' is a matrix transposed to S, x is a n-vector, alpha is a
alpar@1
   326
*  scalar, y is m0-vector.
alpar@1
   327
*
alpar@1
   328
*  Since matrix R is available by rows, the product is computed as a
alpar@1
   329
*  linear combination:
alpar@1
   330
*
alpar@1
   331
*     y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
alpar@1
   332
*
alpar@1
   333
*  where S'[i] is i-th row of S. */
alpar@1
   334
alpar@1
   335
static void st_prod(LPF *lpf, double y[], double a, const double x[])
alpar@1
   336
{     int n = lpf->n;
alpar@1
   337
      int *S_ptr = lpf->S_ptr;
alpar@1
   338
      int *S_len = lpf->S_len;
alpar@1
   339
      int *v_ind = lpf->v_ind;
alpar@1
   340
      double *v_val = lpf->v_val;
alpar@1
   341
      int i, beg, end, ptr;
alpar@1
   342
      double t;
alpar@1
   343
      for (i = 1; i <= n; i++)
alpar@1
   344
      {  if (x[i] == 0.0) continue;
alpar@1
   345
         /* y := y + alpha * S'[i] * x[i] */
alpar@1
   346
         t = a * x[i];
alpar@1
   347
         beg = S_ptr[i];
alpar@1
   348
         end = beg + S_len[i];
alpar@1
   349
         for (ptr = beg; ptr < end; ptr++)
alpar@1
   350
            y[v_ind[ptr]] += t * v_val[ptr];
alpar@1
   351
      }
alpar@1
   352
      return;
alpar@1
   353
}
alpar@1
   354
alpar@1
   355
#if _GLPLPF_DEBUG
alpar@1
   356
/***********************************************************************
alpar@1
   357
*  The routine check_error computes the maximal relative error between
alpar@1
   358
*  left- and right-hand sides for the system B * x = b (if tr is zero)
alpar@1
   359
*  or B' * x = b (if tr is non-zero), where B' is a matrix transposed
alpar@1
   360
*  to B. (This routine is intended for debugging only.) */
alpar@1
   361
alpar@1
   362
static void check_error(LPF *lpf, int tr, const double x[],
alpar@1
   363
      const double b[])
alpar@1
   364
{     int m = lpf->m;
alpar@1
   365
      double *B = lpf->B;
alpar@1
   366
      int i, j;
alpar@1
   367
      double  d, dmax = 0.0, s, t, tmax;
alpar@1
   368
      for (i = 1; i <= m; i++)
alpar@1
   369
      {  s = 0.0;
alpar@1
   370
         tmax = 1.0;
alpar@1
   371
         for (j = 1; j <= m; j++)
alpar@1
   372
         {  if (!tr)
alpar@1
   373
               t = B[m * (i - 1) + j] * x[j];
alpar@1
   374
            else
alpar@1
   375
               t = B[m * (j - 1) + i] * x[j];
alpar@1
   376
            if (tmax < fabs(t)) tmax = fabs(t);
alpar@1
   377
            s += t;
alpar@1
   378
         }
alpar@1
   379
         d = fabs(s - b[i]) / tmax;
alpar@1
   380
         if (dmax < d) dmax = d;
alpar@1
   381
      }
alpar@1
   382
      if (dmax > 1e-8)
alpar@1
   383
         xprintf("%s: dmax = %g; relative error too large\n",
alpar@1
   384
            !tr ? "lpf_ftran" : "lpf_btran", dmax);
alpar@1
   385
      return;
alpar@1
   386
}
alpar@1
   387
#endif
alpar@1
   388
alpar@1
   389
/***********************************************************************
alpar@1
   390
*  NAME
alpar@1
   391
*
alpar@1
   392
*  lpf_ftran - perform forward transformation (solve system B*x = b)
alpar@1
   393
*
alpar@1
   394
*  SYNOPSIS
alpar@1
   395
*
alpar@1
   396
*  #include "glplpf.h"
alpar@1
   397
*  void lpf_ftran(LPF *lpf, double x[]);
alpar@1
   398
*
alpar@1
   399
*  DESCRIPTION
alpar@1
   400
*
alpar@1
   401
*  The routine lpf_ftran performs forward transformation, i.e. solves
alpar@1
   402
*  the system B*x = b, where B is the basis matrix, x is the vector of
alpar@1
   403
*  unknowns to be computed, b is the vector of right-hand sides.
alpar@1
   404
*
alpar@1
   405
*  On entry elements of the vector b should be stored in dense format
alpar@1
   406
*  in locations x[1], ..., x[m], where m is the number of rows. On exit
alpar@1
   407
*  the routine stores elements of the vector x in the same locations.
alpar@1
   408
*
alpar@1
   409
*  BACKGROUND
alpar@1
   410
*
alpar@1
   411
*  Solution of the system B * x = b can be obtained by solving the
alpar@1
   412
*  following augmented system:
alpar@1
   413
*
alpar@1
   414
*     ( B  F^) ( x )   ( b )
alpar@1
   415
*     (      ) (   ) = (   )
alpar@1
   416
*     ( G^ H^) ( y )   ( 0 )
alpar@1
   417
*
alpar@1
   418
*  which, using the main equality, can be written as follows:
alpar@1
   419
*
alpar@1
   420
*       ( L0 0 ) ( U0 R )   ( x )   ( b )
alpar@1
   421
*     P (      ) (      ) Q (   ) = (   )
alpar@1
   422
*       ( S  I ) ( 0  C )   ( y )   ( 0 )
alpar@1
   423
*
alpar@1
   424
*  therefore,
alpar@1
   425
*
alpar@1
   426
*     ( x )      ( U0 R )-1 ( L0 0 )-1    ( b )
alpar@1
   427
*     (   ) = Q' (      )   (      )   P' (   )
alpar@1
   428
*     ( y )      ( 0  C )   ( S  I )      ( 0 )
alpar@1
   429
*
alpar@1
   430
*  Thus, computing the solution includes the following steps:
alpar@1
   431
*
alpar@1
   432
*  1. Compute
alpar@1
   433
*
alpar@1
   434
*     ( f )      ( b )
alpar@1
   435
*     (   ) = P' (   )
alpar@1
   436
*     ( g )      ( 0 )
alpar@1
   437
*
alpar@1
   438
*  2. Solve the system
alpar@1
   439
*
alpar@1
   440
*     ( f1 )   ( L0 0 )-1 ( f )      ( L0 0 ) ( f1 )   ( f )
alpar@1
   441
*     (    ) = (      )   (   )  =>  (      ) (    ) = (   )
alpar@1
   442
*     ( g1 )   ( S  I )   ( g )      ( S  I ) ( g1 )   ( g )
alpar@1
   443
*
alpar@1
   444
*     from which it follows that:
alpar@1
   445
*
alpar@1
   446
*     { L0 * f1      = f      f1 = inv(L0) * f
alpar@1
   447
*     {                   =>
alpar@1
   448
*     {  S * f1 + g1 = g      g1 = g - S * f1
alpar@1
   449
*
alpar@1
   450
*  3. Solve the system
alpar@1
   451
*
alpar@1
   452
*     ( f2 )   ( U0 R )-1 ( f1 )      ( U0 R ) ( f2 )   ( f1 )
alpar@1
   453
*     (    ) = (      )   (    )  =>  (      ) (    ) = (    )
alpar@1
   454
*     ( g2 )   ( 0  C )   ( g1 )      ( 0  C ) ( g2 )   ( g1 )
alpar@1
   455
*
alpar@1
   456
*     from which it follows that:
alpar@1
   457
*
alpar@1
   458
*     { U0 * f2 + R * g2 = f1      f2 = inv(U0) * (f1 - R * g2)
alpar@1
   459
*     {                        =>
alpar@1
   460
*     {           C * g2 = g1      g2 = inv(C) * g1
alpar@1
   461
*
alpar@1
   462
*  4. Compute
alpar@1
   463
*
alpar@1
   464
*     ( x )      ( f2 )
alpar@1
   465
*     (   ) = Q' (    )
alpar@1
   466
*     ( y )      ( g2 )                                               */
alpar@1
   467
alpar@1
   468
void lpf_ftran(LPF *lpf, double x[])
alpar@1
   469
{     int m0 = lpf->m0;
alpar@1
   470
      int m = lpf->m;
alpar@1
   471
      int n  = lpf->n;
alpar@1
   472
      int *P_col = lpf->P_col;
alpar@1
   473
      int *Q_col = lpf->Q_col;
alpar@1
   474
      double *fg = lpf->work1;
alpar@1
   475
      double *f = fg;
alpar@1
   476
      double *g = fg + m0;
alpar@1
   477
      int i, ii;
alpar@1
   478
#if _GLPLPF_DEBUG
alpar@1
   479
      double *b;
alpar@1
   480
#endif
alpar@1
   481
      if (!lpf->valid)
alpar@1
   482
         xfault("lpf_ftran: the factorization is not valid\n");
alpar@1
   483
      xassert(0 <= m && m <= m0 + n);
alpar@1
   484
#if _GLPLPF_DEBUG
alpar@1
   485
      /* save the right-hand side vector */
alpar@1
   486
      b = xcalloc(1+m, sizeof(double));
alpar@1
   487
      for (i = 1; i <= m; i++) b[i] = x[i];
alpar@1
   488
#endif
alpar@1
   489
      /* (f g) := inv(P) * (b 0) */
alpar@1
   490
      for (i = 1; i <= m0 + n; i++)
alpar@1
   491
         fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
alpar@1
   492
      /* f1 := inv(L0) * f */
alpar@1
   493
      luf_f_solve(lpf->luf, 0, f);
alpar@1
   494
      /* g1 := g - S * f1 */
alpar@1
   495
      s_prod(lpf, g, -1.0, f);
alpar@1
   496
      /* g2 := inv(C) * g1 */
alpar@1
   497
      scf_solve_it(lpf->scf, 0, g);
alpar@1
   498
      /* f2 := inv(U0) * (f1 - R * g2) */
alpar@1
   499
      r_prod(lpf, f, -1.0, g);
alpar@1
   500
      luf_v_solve(lpf->luf, 0, f);
alpar@1
   501
      /* (x y) := inv(Q) * (f2 g2) */
alpar@1
   502
      for (i = 1; i <= m; i++)
alpar@1
   503
         x[i] = fg[Q_col[i]];
alpar@1
   504
#if _GLPLPF_DEBUG
alpar@1
   505
      /* check relative error in solution */
alpar@1
   506
      check_error(lpf, 0, x, b);
alpar@1
   507
      xfree(b);
alpar@1
   508
#endif
alpar@1
   509
      return;
alpar@1
   510
}
alpar@1
   511
alpar@1
   512
/***********************************************************************
alpar@1
   513
*  NAME
alpar@1
   514
*
alpar@1
   515
*  lpf_btran - perform backward transformation (solve system B'*x = b)
alpar@1
   516
*
alpar@1
   517
*  SYNOPSIS
alpar@1
   518
*
alpar@1
   519
*  #include "glplpf.h"
alpar@1
   520
*  void lpf_btran(LPF *lpf, double x[]);
alpar@1
   521
*
alpar@1
   522
*  DESCRIPTION
alpar@1
   523
*
alpar@1
   524
*  The routine lpf_btran performs backward transformation, i.e. solves
alpar@1
   525
*  the system B'*x = b, where B' is a matrix transposed to the basis
alpar@1
   526
*  matrix B, x is the vector of unknowns to be computed, b is the vector
alpar@1
   527
*  of right-hand sides.
alpar@1
   528
*
alpar@1
   529
*  On entry elements of the vector b should be stored in dense format
alpar@1
   530
*  in locations x[1], ..., x[m], where m is the number of rows. On exit
alpar@1
   531
*  the routine stores elements of the vector x in the same locations.
alpar@1
   532
*
alpar@1
   533
*  BACKGROUND
alpar@1
   534
*
alpar@1
   535
*  Solution of the system B' * x = b, where B' is a matrix transposed
alpar@1
   536
*  to B, can be obtained by solving the following augmented system:
alpar@1
   537
*
alpar@1
   538
*     ( B  F^)T ( x )   ( b )
alpar@1
   539
*     (      )  (   ) = (   )
alpar@1
   540
*     ( G^ H^)  ( y )   ( 0 )
alpar@1
   541
*
alpar@1
   542
*  which, using the main equality, can be written as follows:
alpar@1
   543
*
alpar@1
   544
*      T ( U0 R )T ( L0 0 )T  T ( x )   ( b )
alpar@1
   545
*     Q  (      )  (      )  P  (   ) = (   )
alpar@1
   546
*        ( 0  C )  ( S  I )     ( y )   ( 0 )
alpar@1
   547
*
alpar@1
   548
*  or, equivalently, as follows:
alpar@1
   549
*
alpar@1
   550
*        ( U'0 0 ) ( L'0 S')    ( x )   ( b )
alpar@1
   551
*     Q' (       ) (       ) P' (   ) = (   )
alpar@1
   552
*        ( R'  C') ( 0   I )    ( y )   ( 0 )
alpar@1
   553
*
alpar@1
   554
*  therefore,
alpar@1
   555
*
alpar@1
   556
*     ( x )     ( L'0 S')-1 ( U'0 0 )-1   ( b )
alpar@1
   557
*     (   ) = P (       )   (       )   Q (   )
alpar@1
   558
*     ( y )     ( 0   I )   ( R'  C')     ( 0 )
alpar@1
   559
*
alpar@1
   560
*  Thus, computing the solution includes the following steps:
alpar@1
   561
*
alpar@1
   562
*  1. Compute
alpar@1
   563
*
alpar@1
   564
*     ( f )     ( b )
alpar@1
   565
*     (   ) = Q (   )
alpar@1
   566
*     ( g )     ( 0 )
alpar@1
   567
*
alpar@1
   568
*  2. Solve the system
alpar@1
   569
*
alpar@1
   570
*     ( f1 )   ( U'0 0 )-1 ( f )      ( U'0 0 ) ( f1 )   ( f )
alpar@1
   571
*     (    ) = (       )   (   )  =>  (       ) (    ) = (   )
alpar@1
   572
*     ( g1 )   ( R'  C')   ( g )      ( R'  C') ( g1 )   ( g )
alpar@1
   573
*
alpar@1
   574
*     from which it follows that:
alpar@1
   575
*
alpar@1
   576
*     { U'0 * f1           = f      f1 = inv(U'0) * f
alpar@1
   577
*     {                         =>
alpar@1
   578
*     { R'  * f1 + C' * g1 = g      g1 = inv(C') * (g - R' * f1)
alpar@1
   579
*
alpar@1
   580
*  3. Solve the system
alpar@1
   581
*
alpar@1
   582
*     ( f2 )   ( L'0 S')-1 ( f1 )      ( L'0 S') ( f2 )   ( f1 )
alpar@1
   583
*     (    ) = (       )   (    )  =>  (       ) (    ) = (    )
alpar@1
   584
*     ( g2 )   ( 0   I )   ( g1 )      ( 0   I ) ( g2 )   ( g1 )
alpar@1
   585
*
alpar@1
   586
*     from which it follows that:
alpar@1
   587
*
alpar@1
   588
*     { L'0 * f2 + S' * g2 = f1
alpar@1
   589
*     {                          =>  f2 = inv(L'0) * ( f1 - S' * g2)
alpar@1
   590
*     {                 g2 = g1
alpar@1
   591
*
alpar@1
   592
*  4. Compute
alpar@1
   593
*
alpar@1
   594
*     ( x )     ( f2 )
alpar@1
   595
*     (   ) = P (    )
alpar@1
   596
*     ( y )     ( g2 )                                                */
alpar@1
   597
alpar@1
   598
void lpf_btran(LPF *lpf, double x[])
alpar@1
   599
{     int m0 = lpf->m0;
alpar@1
   600
      int m = lpf->m;
alpar@1
   601
      int n = lpf->n;
alpar@1
   602
      int *P_row = lpf->P_row;
alpar@1
   603
      int *Q_row = lpf->Q_row;
alpar@1
   604
      double *fg = lpf->work1;
alpar@1
   605
      double *f = fg;
alpar@1
   606
      double *g = fg + m0;
alpar@1
   607
      int i, ii;
alpar@1
   608
#if _GLPLPF_DEBUG
alpar@1
   609
      double *b;
alpar@1
   610
#endif
alpar@1
   611
      if (!lpf->valid)
alpar@1
   612
         xfault("lpf_btran: the factorization is not valid\n");
alpar@1
   613
      xassert(0 <= m && m <= m0 + n);
alpar@1
   614
#if _GLPLPF_DEBUG
alpar@1
   615
      /* save the right-hand side vector */
alpar@1
   616
      b = xcalloc(1+m, sizeof(double));
alpar@1
   617
      for (i = 1; i <= m; i++) b[i] = x[i];
alpar@1
   618
#endif
alpar@1
   619
      /* (f g) := Q * (b 0) */
alpar@1
   620
      for (i = 1; i <= m0 + n; i++)
alpar@1
   621
         fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
alpar@1
   622
      /* f1 := inv(U'0) * f */
alpar@1
   623
      luf_v_solve(lpf->luf, 1, f);
alpar@1
   624
      /* g1 := inv(C') * (g - R' * f1) */
alpar@1
   625
      rt_prod(lpf, g, -1.0, f);
alpar@1
   626
      scf_solve_it(lpf->scf, 1, g);
alpar@1
   627
      /* g2 := g1 */
alpar@1
   628
      g = g;
alpar@1
   629
      /* f2 := inv(L'0) * (f1 - S' * g2) */
alpar@1
   630
      st_prod(lpf, f, -1.0, g);
alpar@1
   631
      luf_f_solve(lpf->luf, 1, f);
alpar@1
   632
      /* (x y) := P * (f2 g2) */
alpar@1
   633
      for (i = 1; i <= m; i++)
alpar@1
   634
         x[i] = fg[P_row[i]];
alpar@1
   635
#if _GLPLPF_DEBUG
alpar@1
   636
      /* check relative error in solution */
alpar@1
   637
      check_error(lpf, 1, x, b);
alpar@1
   638
      xfree(b);
alpar@1
   639
#endif
alpar@1
   640
      return;
alpar@1
   641
}
alpar@1
   642
alpar@1
   643
/***********************************************************************
alpar@1
   644
*  The routine enlarge_sva enlarges the Sparse Vector Area to new_size
alpar@1
   645
*  locations by reallocating the arrays v_ind and v_val. */
alpar@1
   646
alpar@1
   647
static void enlarge_sva(LPF *lpf, int new_size)
alpar@1
   648
{     int v_size = lpf->v_size;
alpar@1
   649
      int used = lpf->v_ptr - 1;
alpar@1
   650
      int *v_ind = lpf->v_ind;
alpar@1
   651
      double *v_val = lpf->v_val;
alpar@1
   652
      xassert(v_size < new_size);
alpar@1
   653
      while (v_size < new_size) v_size += v_size;
alpar@1
   654
      lpf->v_size = v_size;
alpar@1
   655
      lpf->v_ind = xcalloc(1+v_size, sizeof(int));
alpar@1
   656
      lpf->v_val = xcalloc(1+v_size, sizeof(double));
alpar@1
   657
      xassert(used >= 0);
alpar@1
   658
      memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
alpar@1
   659
      memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
alpar@1
   660
      xfree(v_ind);
alpar@1
   661
      xfree(v_val);
alpar@1
   662
      return;
alpar@1
   663
}
alpar@1
   664
alpar@1
   665
/***********************************************************************
alpar@1
   666
*  NAME
alpar@1
   667
*
alpar@1
   668
*  lpf_update_it - update LP basis factorization
alpar@1
   669
*
alpar@1
   670
*  SYNOPSIS
alpar@1
   671
*
alpar@1
   672
*  #include "glplpf.h"
alpar@1
   673
*  int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
alpar@1
   674
*     const double val[]);
alpar@1
   675
*
alpar@1
   676
*  DESCRIPTION
alpar@1
   677
*
alpar@1
   678
*  The routine lpf_update_it updates the factorization of the basis
alpar@1
   679
*  matrix B after replacing its j-th column by a new vector.
alpar@1
   680
*
alpar@1
   681
*  The parameter j specifies the number of column of B, which has been
alpar@1
   682
*  replaced, 1 <= j <= m, where m is the order of B.
alpar@1
   683
*
alpar@1
   684
*  The parameter bh specifies the basis header entry for the new column
alpar@1
   685
*  of B, which is the number of the new column in some original matrix.
alpar@1
   686
*  This parameter is optional and can be specified as 0.
alpar@1
   687
*
alpar@1
   688
*  Row indices and numerical values of non-zero elements of the new
alpar@1
   689
*  column of B should be placed in locations ind[1], ..., ind[len] and
alpar@1
   690
*  val[1], ..., val[len], resp., where len is the number of non-zeros
alpar@1
   691
*  in the column. Neither zero nor duplicate elements are allowed.
alpar@1
   692
*
alpar@1
   693
*  RETURNS
alpar@1
   694
*
alpar@1
   695
*  0  The factorization has been successfully updated.
alpar@1
   696
*
alpar@1
   697
*  LPF_ESING
alpar@1
   698
*     New basis B is singular within the working precision.
alpar@1
   699
*
alpar@1
   700
*  LPF_ELIMIT
alpar@1
   701
*     Maximal number of additional rows and columns has been reached.
alpar@1
   702
*
alpar@1
   703
*  BACKGROUND
alpar@1
   704
*
alpar@1
   705
*  Let j-th column of the current basis matrix B have to be replaced by
alpar@1
   706
*  a new column a. This replacement is equivalent to removing the old
alpar@1
   707
*  j-th column by fixing it at zero and introducing the new column as
alpar@1
   708
*  follows:
alpar@1
   709
*
alpar@1
   710
*                   ( B   F^| a )
alpar@1
   711
*     ( B  F^)      (       |   )
alpar@1
   712
*     (      ) ---> ( G^  H^| 0 )
alpar@1
   713
*     ( G^ H^)      (-------+---)
alpar@1
   714
*                   ( e'j 0 | 0 )
alpar@1
   715
*
alpar@1
   716
*  where ej is a unit vector with 1 in j-th position which used to fix
alpar@1
   717
*  the old j-th column of B (at zero). Then using the main equality we
alpar@1
   718
*  have:
alpar@1
   719
*
alpar@1
   720
*     ( B   F^| a )            ( B0  F | f )
alpar@1
   721
*     (       |   )   ( P  0 ) (       |   ) ( Q  0 )
alpar@1
   722
*     ( G^  H^| 0 ) = (      ) ( G   H | g ) (      ) =
alpar@1
   723
*     (-------+---)   ( 0  1 ) (-------+---) ( 0  1 )
alpar@1
   724
*     ( e'j 0 | 0 )            ( v'  w'| 0 )
alpar@1
   725
*
alpar@1
   726
*       [   ( B0  F )|   ( f ) ]            [   ( B0 F )  |   ( f ) ]
alpar@1
   727
*       [ P (       )| P (   ) ] ( Q  0 )   [ P (      ) Q| P (   ) ]
alpar@1
   728
*     = [   ( G   H )|   ( g ) ] (      ) = [   ( G  H )  |   ( g ) ]
alpar@1
   729
*       [------------+-------- ] ( 0  1 )   [-------------+---------]
alpar@1
   730
*       [   ( v'  w')|     0   ]            [   ( v' w') Q|    0    ]
alpar@1
   731
*
alpar@1
   732
*  where:
alpar@1
   733
*
alpar@1
   734
*     ( a )     ( f )      ( f )        ( a )
alpar@1
   735
*     (   ) = P (   )  =>  (   ) = P' * (   )
alpar@1
   736
*     ( 0 )     ( g )      ( g )        ( 0 )
alpar@1
   737
*
alpar@1
   738
*                                 ( ej )      ( v )    ( v )     ( ej )
alpar@1
   739
*     ( e'j  0 ) = ( v' w' ) Q => (    ) = Q' (   ) => (   ) = Q (    )
alpar@1
   740
*                                 ( 0  )      ( w )    ( w )     ( 0  )
alpar@1
   741
*
alpar@1
   742
*  On the other hand:
alpar@1
   743
*
alpar@1
   744
*              ( B0| F  f )
alpar@1
   745
*     ( P  0 ) (---+------) ( Q  0 )         ( B0    new F )
alpar@1
   746
*     (      ) ( G | H  g ) (      ) = new P (             ) new Q
alpar@1
   747
*     ( 0  1 ) (   |      ) ( 0  1 )         ( new G new H )
alpar@1
   748
*              ( v'| w' 0 )
alpar@1
   749
*
alpar@1
   750
*  where:
alpar@1
   751
*                               ( G )           ( H  g )
alpar@1
   752
*     new F = ( F  f ), new G = (   ),  new H = (      ),
alpar@1
   753
*                               ( v')           ( w' 0 )
alpar@1
   754
*
alpar@1
   755
*             ( P  0 )           ( Q  0 )
alpar@1
   756
*     new P = (      ) , new Q = (      ) .
alpar@1
   757
*             ( 0  1 )           ( 0  1 )
alpar@1
   758
*
alpar@1
   759
*  The factorization structure for the new augmented matrix remains the
alpar@1
   760
*  same, therefore:
alpar@1
   761
*
alpar@1
   762
*           ( B0    new F )         ( L0     0 ) ( U0 new R )
alpar@1
   763
*     new P (             ) new Q = (          ) (          )
alpar@1
   764
*           ( new G new H )         ( new S  I ) ( 0  new C )
alpar@1
   765
*
alpar@1
   766
*  where:
alpar@1
   767
*
alpar@1
   768
*     new F = L0 * new R  =>
alpar@1
   769
*
alpar@1
   770
*     new R = inv(L0) * new F = inv(L0) * (F  f) = ( R  inv(L0)*f )
alpar@1
   771
*
alpar@1
   772
*     new G = new S * U0  =>
alpar@1
   773
*
alpar@1
   774
*                               ( G )             (     S      )
alpar@1
   775
*     new S = new G * inv(U0) = (   ) * inv(U0) = (            )
alpar@1
   776
*                               ( v')             ( v'*inv(U0) )
alpar@1
   777
*
alpar@1
   778
*     new H = new S * new R + new C  =>
alpar@1
   779
*
alpar@1
   780
*     new C = new H - new S * new R =
alpar@1
   781
*
alpar@1
   782
*             ( H  g )   (     S      )
alpar@1
   783
*           = (      ) - (            ) * ( R  inv(L0)*f ) =
alpar@1
   784
*             ( w' 0 )   ( v'*inv(U0) )
alpar@1
   785
*
alpar@1
   786
*             ( H - S*R           g - S*inv(L0)*f      )   ( C  x )
alpar@1
   787
*           = (                                        ) = (      )
alpar@1
   788
*             ( w'- v'*inv(U0)*R  -v'*inv(U0)*inv(L0)*f)   ( y' z )
alpar@1
   789
*
alpar@1
   790
*  Note that new C is resulted by expanding old C with new column x,
alpar@1
   791
*  row y', and diagonal element z, where:
alpar@1
   792
*
alpar@1
   793
*     x = g - S * inv(L0) * f = g - S * (new column of R)
alpar@1
   794
*
alpar@1
   795
*     y = w - R'* inv(U'0)* v = w - R'* (new row of S)
alpar@1
   796
*
alpar@1
   797
*     z = - (new row of S) * (new column of R)
alpar@1
   798
*
alpar@1
   799
*  Finally, to replace old B by new B we have to permute j-th and last
alpar@1
   800
*  (just added) columns of the matrix
alpar@1
   801
*
alpar@1
   802
*     ( B   F^| a )
alpar@1
   803
*     (       |   )
alpar@1
   804
*     ( G^  H^| 0 )
alpar@1
   805
*     (-------+---)
alpar@1
   806
*     ( e'j 0 | 0 )
alpar@1
   807
*
alpar@1
   808
*  and to keep the main equality do the same for matrix Q. */
alpar@1
   809
alpar@1
   810
int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
alpar@1
   811
      const double val[])
alpar@1
   812
{     int m0 = lpf->m0;
alpar@1
   813
      int m = lpf->m;
alpar@1
   814
#if _GLPLPF_DEBUG
alpar@1
   815
      double *B = lpf->B;
alpar@1
   816
#endif
alpar@1
   817
      int n = lpf->n;
alpar@1
   818
      int *R_ptr = lpf->R_ptr;
alpar@1
   819
      int *R_len = lpf->R_len;
alpar@1
   820
      int *S_ptr = lpf->S_ptr;
alpar@1
   821
      int *S_len = lpf->S_len;
alpar@1
   822
      int *P_row = lpf->P_row;
alpar@1
   823
      int *P_col = lpf->P_col;
alpar@1
   824
      int *Q_row = lpf->Q_row;
alpar@1
   825
      int *Q_col = lpf->Q_col;
alpar@1
   826
      int v_ptr = lpf->v_ptr;
alpar@1
   827
      int *v_ind = lpf->v_ind;
alpar@1
   828
      double *v_val = lpf->v_val;
alpar@1
   829
      double *a = lpf->work2; /* new column */
alpar@1
   830
      double *fg = lpf->work1, *f = fg, *g = fg + m0;
alpar@1
   831
      double *vw = lpf->work2, *v = vw, *w = vw + m0;
alpar@1
   832
      double *x = g, *y = w, z;
alpar@1
   833
      int i, ii, k, ret;
alpar@1
   834
      xassert(bh == bh);
alpar@1
   835
      if (!lpf->valid)
alpar@1
   836
         xfault("lpf_update_it: the factorization is not valid\n");
alpar@1
   837
      if (!(1 <= j && j <= m))
alpar@1
   838
         xfault("lpf_update_it: j = %d; column number out of range\n",
alpar@1
   839
            j);
alpar@1
   840
      xassert(0 <= m && m <= m0 + n);
alpar@1
   841
      /* check if the basis factorization can be expanded */
alpar@1
   842
      if (n == lpf->n_max)
alpar@1
   843
      {  lpf->valid = 0;
alpar@1
   844
         ret = LPF_ELIMIT;
alpar@1
   845
         goto done;
alpar@1
   846
      }
alpar@1
   847
      /* convert new j-th column of B to dense format */
alpar@1
   848
      for (i = 1; i <= m; i++)
alpar@1
   849
         a[i] = 0.0;
alpar@1
   850
      for (k = 1; k <= len; k++)
alpar@1
   851
      {  i = ind[k];
alpar@1
   852
         if (!(1 <= i && i <= m))
alpar@1
   853
            xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
alpar@1
   854
               "e\n", k, i);
alpar@1
   855
         if (a[i] != 0.0)
alpar@1
   856
            xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
alpar@1
   857
               "t allowed\n", k, i);
alpar@1
   858
         if (val[k] == 0.0)
alpar@1
   859
            xfault("lpf_update_it: val[%d] = %g; zero element not allow"
alpar@1
   860
               "ed\n", k, val[k]);
alpar@1
   861
         a[i] = val[k];
alpar@1
   862
      }
alpar@1
   863
#if _GLPLPF_DEBUG
alpar@1
   864
      /* change column in the basis matrix for debugging */
alpar@1
   865
      for (i = 1; i <= m; i++)
alpar@1
   866
         B[(i - 1) * m + j] = a[i];
alpar@1
   867
#endif
alpar@1
   868
      /* (f g) := inv(P) * (a 0) */
alpar@1
   869
      for (i = 1; i <= m0+n; i++)
alpar@1
   870
         fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
alpar@1
   871
      /* (v w) := Q * (ej 0) */
alpar@1
   872
      for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
alpar@1
   873
      vw[Q_col[j]] = 1.0;
alpar@1
   874
      /* f1 := inv(L0) * f (new column of R) */
alpar@1
   875
      luf_f_solve(lpf->luf, 0, f);
alpar@1
   876
      /* v1 := inv(U'0) * v (new row of S) */
alpar@1
   877
      luf_v_solve(lpf->luf, 1, v);
alpar@1
   878
      /* we need at most 2 * m0 available locations in the SVA to store
alpar@1
   879
         new column of matrix R and new row of matrix S */
alpar@1
   880
      if (lpf->v_size < v_ptr + m0 + m0)
alpar@1
   881
      {  enlarge_sva(lpf, v_ptr + m0 + m0);
alpar@1
   882
         v_ind = lpf->v_ind;
alpar@1
   883
         v_val = lpf->v_val;
alpar@1
   884
      }
alpar@1
   885
      /* store new column of R */
alpar@1
   886
      R_ptr[n+1] = v_ptr;
alpar@1
   887
      for (i = 1; i <= m0; i++)
alpar@1
   888
      {  if (f[i] != 0.0)
alpar@1
   889
            v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
alpar@1
   890
      }
alpar@1
   891
      R_len[n+1] = v_ptr - lpf->v_ptr;
alpar@1
   892
      lpf->v_ptr = v_ptr;
alpar@1
   893
      /* store new row of S */
alpar@1
   894
      S_ptr[n+1] = v_ptr;
alpar@1
   895
      for (i = 1; i <= m0; i++)
alpar@1
   896
      {  if (v[i] != 0.0)
alpar@1
   897
            v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
alpar@1
   898
      }
alpar@1
   899
      S_len[n+1] = v_ptr - lpf->v_ptr;
alpar@1
   900
      lpf->v_ptr = v_ptr;
alpar@1
   901
      /* x := g - S * f1 (new column of C) */
alpar@1
   902
      s_prod(lpf, x, -1.0, f);
alpar@1
   903
      /* y := w - R' * v1 (new row of C) */
alpar@1
   904
      rt_prod(lpf, y, -1.0, v);
alpar@1
   905
      /* z := - v1 * f1 (new diagonal element of C) */
alpar@1
   906
      z = 0.0;
alpar@1
   907
      for (i = 1; i <= m0; i++) z -= v[i] * f[i];
alpar@1
   908
      /* update factorization of new matrix C */
alpar@1
   909
      switch (scf_update_exp(lpf->scf, x, y, z))
alpar@1
   910
      {  case 0:
alpar@1
   911
            break;
alpar@1
   912
         case SCF_ESING:
alpar@1
   913
            lpf->valid = 0;
alpar@1
   914
            ret = LPF_ESING;
alpar@1
   915
            goto done;
alpar@1
   916
         case SCF_ELIMIT:
alpar@1
   917
            xassert(lpf != lpf);
alpar@1
   918
         default:
alpar@1
   919
            xassert(lpf != lpf);
alpar@1
   920
      }
alpar@1
   921
      /* expand matrix P */
alpar@1
   922
      P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
alpar@1
   923
      /* expand matrix Q */
alpar@1
   924
      Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
alpar@1
   925
      /* permute j-th and last (just added) column of matrix Q */
alpar@1
   926
      i = Q_col[j], ii = Q_col[m0+n+1];
alpar@1
   927
      Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
alpar@1
   928
      Q_row[ii] = j, Q_col[j] = ii;
alpar@1
   929
      /* increase the number of additional rows and columns */
alpar@1
   930
      lpf->n++;
alpar@1
   931
      xassert(lpf->n <= lpf->n_max);
alpar@1
   932
      /* the factorization has been successfully updated */
alpar@1
   933
      ret = 0;
alpar@1
   934
done: /* return to the calling program */
alpar@1
   935
      return ret;
alpar@1
   936
}
alpar@1
   937
alpar@1
   938
/***********************************************************************
alpar@1
   939
*  NAME
alpar@1
   940
*
alpar@1
   941
*  lpf_delete_it - delete LP basis factorization
alpar@1
   942
*
alpar@1
   943
*  SYNOPSIS
alpar@1
   944
*
alpar@1
   945
*  #include "glplpf.h"
alpar@1
   946
*  void lpf_delete_it(LPF *lpf)
alpar@1
   947
*
alpar@1
   948
*  DESCRIPTION
alpar@1
   949
*
alpar@1
   950
*  The routine lpf_delete_it deletes LP basis factorization specified
alpar@1
   951
*  by the parameter lpf and frees all memory allocated to this program
alpar@1
   952
*  object. */
alpar@1
   953
alpar@1
   954
void lpf_delete_it(LPF *lpf)
alpar@1
   955
{     luf_delete_it(lpf->luf);
alpar@1
   956
#if _GLPLPF_DEBUG
alpar@1
   957
      if (lpf->B != NULL) xfree(lpf->B);
alpar@1
   958
#else
alpar@1
   959
      xassert(lpf->B == NULL);
alpar@1
   960
#endif
alpar@1
   961
      if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
alpar@1
   962
      if (lpf->R_len != NULL) xfree(lpf->R_len);
alpar@1
   963
      if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
alpar@1
   964
      if (lpf->S_len != NULL) xfree(lpf->S_len);
alpar@1
   965
      if (lpf->scf != NULL) scf_delete_it(lpf->scf);
alpar@1
   966
      if (lpf->P_row != NULL) xfree(lpf->P_row);
alpar@1
   967
      if (lpf->P_col != NULL) xfree(lpf->P_col);
alpar@1
   968
      if (lpf->Q_row != NULL) xfree(lpf->Q_row);
alpar@1
   969
      if (lpf->Q_col != NULL) xfree(lpf->Q_col);
alpar@1
   970
      if (lpf->v_ind != NULL) xfree(lpf->v_ind);
alpar@1
   971
      if (lpf->v_val != NULL) xfree(lpf->v_val);
alpar@1
   972
      if (lpf->work1 != NULL) xfree(lpf->work1);
alpar@1
   973
      if (lpf->work2 != NULL) xfree(lpf->work2);
alpar@1
   974
      xfree(lpf);
alpar@1
   975
      return;
alpar@1
   976
}
alpar@1
   977
alpar@1
   978
/* eof */