src/glplux.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
/* glplux.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 "glplux.h"
alpar@1
    26
#define xfault xerror
alpar@1
    27
#define dmp_create_poolx(size) dmp_create_pool()
alpar@1
    28
alpar@1
    29
/*----------------------------------------------------------------------
alpar@1
    30
// lux_create - create LU-factorization.
alpar@1
    31
//
alpar@1
    32
// SYNOPSIS
alpar@1
    33
//
alpar@1
    34
// #include "glplux.h"
alpar@1
    35
// LUX *lux_create(int n);
alpar@1
    36
//
alpar@1
    37
// DESCRIPTION
alpar@1
    38
//
alpar@1
    39
// The routine lux_create creates LU-factorization data structure for
alpar@1
    40
// a matrix of the order n. Initially the factorization corresponds to
alpar@1
    41
// the unity matrix (F = V = P = Q = I, so A = I).
alpar@1
    42
//
alpar@1
    43
// RETURNS
alpar@1
    44
//
alpar@1
    45
// The routine returns a pointer to the created LU-factorization data
alpar@1
    46
// structure, which represents the unity matrix of the order n. */
alpar@1
    47
alpar@1
    48
LUX *lux_create(int n)
alpar@1
    49
{     LUX *lux;
alpar@1
    50
      int k;
alpar@1
    51
      if (n < 1)
alpar@1
    52
         xfault("lux_create: n = %d; invalid parameter\n", n);
alpar@1
    53
      lux = xmalloc(sizeof(LUX));
alpar@1
    54
      lux->n = n;
alpar@1
    55
      lux->pool = dmp_create_poolx(sizeof(LUXELM));
alpar@1
    56
      lux->F_row = xcalloc(1+n, sizeof(LUXELM *));
alpar@1
    57
      lux->F_col = xcalloc(1+n, sizeof(LUXELM *));
alpar@1
    58
      lux->V_piv = xcalloc(1+n, sizeof(mpq_t));
alpar@1
    59
      lux->V_row = xcalloc(1+n, sizeof(LUXELM *));
alpar@1
    60
      lux->V_col = xcalloc(1+n, sizeof(LUXELM *));
alpar@1
    61
      lux->P_row = xcalloc(1+n, sizeof(int));
alpar@1
    62
      lux->P_col = xcalloc(1+n, sizeof(int));
alpar@1
    63
      lux->Q_row = xcalloc(1+n, sizeof(int));
alpar@1
    64
      lux->Q_col = xcalloc(1+n, sizeof(int));
alpar@1
    65
      for (k = 1; k <= n; k++)
alpar@1
    66
      {  lux->F_row[k] = lux->F_col[k] = NULL;
alpar@1
    67
         mpq_init(lux->V_piv[k]);
alpar@1
    68
         mpq_set_si(lux->V_piv[k], 1, 1);
alpar@1
    69
         lux->V_row[k] = lux->V_col[k] = NULL;
alpar@1
    70
         lux->P_row[k] = lux->P_col[k] = k;
alpar@1
    71
         lux->Q_row[k] = lux->Q_col[k] = k;
alpar@1
    72
      }
alpar@1
    73
      lux->rank = n;
alpar@1
    74
      return lux;
alpar@1
    75
}
alpar@1
    76
alpar@1
    77
/*----------------------------------------------------------------------
alpar@1
    78
// initialize - initialize LU-factorization data structures.
alpar@1
    79
//
alpar@1
    80
// This routine initializes data structures for subsequent computing
alpar@1
    81
// the LU-factorization of a given matrix A, which is specified by the
alpar@1
    82
// formal routine col. On exit V = A and F = P = Q = I, where I is the
alpar@1
    83
// unity matrix. */
alpar@1
    84
alpar@1
    85
static void initialize(LUX *lux, int (*col)(void *info, int j,
alpar@1
    86
      int ind[], mpq_t val[]), void *info, LUXWKA *wka)
alpar@1
    87
{     int n = lux->n;
alpar@1
    88
      DMP *pool = lux->pool;
alpar@1
    89
      LUXELM **F_row = lux->F_row;
alpar@1
    90
      LUXELM **F_col = lux->F_col;
alpar@1
    91
      mpq_t *V_piv = lux->V_piv;
alpar@1
    92
      LUXELM **V_row = lux->V_row;
alpar@1
    93
      LUXELM **V_col = lux->V_col;
alpar@1
    94
      int *P_row = lux->P_row;
alpar@1
    95
      int *P_col = lux->P_col;
alpar@1
    96
      int *Q_row = lux->Q_row;
alpar@1
    97
      int *Q_col = lux->Q_col;
alpar@1
    98
      int *R_len = wka->R_len;
alpar@1
    99
      int *R_head = wka->R_head;
alpar@1
   100
      int *R_prev = wka->R_prev;
alpar@1
   101
      int *R_next = wka->R_next;
alpar@1
   102
      int *C_len = wka->C_len;
alpar@1
   103
      int *C_head = wka->C_head;
alpar@1
   104
      int *C_prev = wka->C_prev;
alpar@1
   105
      int *C_next = wka->C_next;
alpar@1
   106
      LUXELM *fij, *vij;
alpar@1
   107
      int i, j, k, len, *ind;
alpar@1
   108
      mpq_t *val;
alpar@1
   109
      /* F := I */
alpar@1
   110
      for (i = 1; i <= n; i++)
alpar@1
   111
      {  while (F_row[i] != NULL)
alpar@1
   112
         {  fij = F_row[i], F_row[i] = fij->r_next;
alpar@1
   113
            mpq_clear(fij->val);
alpar@1
   114
            dmp_free_atom(pool, fij, sizeof(LUXELM));
alpar@1
   115
         }
alpar@1
   116
      }
alpar@1
   117
      for (j = 1; j <= n; j++) F_col[j] = NULL;
alpar@1
   118
      /* V := 0 */
alpar@1
   119
      for (k = 1; k <= n; k++) mpq_set_si(V_piv[k], 0, 1);
alpar@1
   120
      for (i = 1; i <= n; i++)
alpar@1
   121
      {  while (V_row[i] != NULL)
alpar@1
   122
         {  vij = V_row[i], V_row[i] = vij->r_next;
alpar@1
   123
            mpq_clear(vij->val);
alpar@1
   124
            dmp_free_atom(pool, vij, sizeof(LUXELM));
alpar@1
   125
         }
alpar@1
   126
      }
alpar@1
   127
      for (j = 1; j <= n; j++) V_col[j] = NULL;
alpar@1
   128
      /* V := A */
alpar@1
   129
      ind = xcalloc(1+n, sizeof(int));
alpar@1
   130
      val = xcalloc(1+n, sizeof(mpq_t));
alpar@1
   131
      for (k = 1; k <= n; k++) mpq_init(val[k]);
alpar@1
   132
      for (j = 1; j <= n; j++)
alpar@1
   133
      {  /* obtain j-th column of matrix A */
alpar@1
   134
         len = col(info, j, ind, val);
alpar@1
   135
         if (!(0 <= len && len <= n))
alpar@1
   136
            xfault("lux_decomp: j = %d: len = %d; invalid column length"
alpar@1
   137
               "\n", j, len);
alpar@1
   138
         /* copy elements of j-th column to matrix V */
alpar@1
   139
         for (k = 1; k <= len; k++)
alpar@1
   140
         {  /* get row index of a[i,j] */
alpar@1
   141
            i = ind[k];
alpar@1
   142
            if (!(1 <= i && i <= n))
alpar@1
   143
               xfault("lux_decomp: j = %d: i = %d; row index out of ran"
alpar@1
   144
                  "ge\n", j, i);
alpar@1
   145
            /* check for duplicate indices */
alpar@1
   146
            if (V_row[i] != NULL && V_row[i]->j == j)
alpar@1
   147
               xfault("lux_decomp: j = %d: i = %d; duplicate row indice"
alpar@1
   148
                  "s not allowed\n", j, i);
alpar@1
   149
            /* check for zero value */
alpar@1
   150
            if (mpq_sgn(val[k]) == 0)
alpar@1
   151
               xfault("lux_decomp: j = %d: i = %d; zero elements not al"
alpar@1
   152
                  "lowed\n", j, i);
alpar@1
   153
            /* add new element v[i,j] = a[i,j] to V */
alpar@1
   154
            vij = dmp_get_atom(pool, sizeof(LUXELM));
alpar@1
   155
            vij->i = i, vij->j = j;
alpar@1
   156
            mpq_init(vij->val);
alpar@1
   157
            mpq_set(vij->val, val[k]);
alpar@1
   158
            vij->r_prev = NULL;
alpar@1
   159
            vij->r_next = V_row[i];
alpar@1
   160
            vij->c_prev = NULL;
alpar@1
   161
            vij->c_next = V_col[j];
alpar@1
   162
            if (vij->r_next != NULL) vij->r_next->r_prev = vij;
alpar@1
   163
            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
alpar@1
   164
            V_row[i] = V_col[j] = vij;
alpar@1
   165
         }
alpar@1
   166
      }
alpar@1
   167
      xfree(ind);
alpar@1
   168
      for (k = 1; k <= n; k++) mpq_clear(val[k]);
alpar@1
   169
      xfree(val);
alpar@1
   170
      /* P := Q := I */
alpar@1
   171
      for (k = 1; k <= n; k++)
alpar@1
   172
         P_row[k] = P_col[k] = Q_row[k] = Q_col[k] = k;
alpar@1
   173
      /* the rank of A and V is not determined yet */
alpar@1
   174
      lux->rank = -1;
alpar@1
   175
      /* initially the entire matrix V is active */
alpar@1
   176
      /* determine its row lengths */
alpar@1
   177
      for (i = 1; i <= n; i++)
alpar@1
   178
      {  len = 0;
alpar@1
   179
         for (vij = V_row[i]; vij != NULL; vij = vij->r_next) len++;
alpar@1
   180
         R_len[i] = len;
alpar@1
   181
      }
alpar@1
   182
      /* build linked lists of active rows */
alpar@1
   183
      for (len = 0; len <= n; len++) R_head[len] = 0;
alpar@1
   184
      for (i = 1; i <= n; i++)
alpar@1
   185
      {  len = R_len[i];
alpar@1
   186
         R_prev[i] = 0;
alpar@1
   187
         R_next[i] = R_head[len];
alpar@1
   188
         if (R_next[i] != 0) R_prev[R_next[i]] = i;
alpar@1
   189
         R_head[len] = i;
alpar@1
   190
      }
alpar@1
   191
      /* determine its column lengths */
alpar@1
   192
      for (j = 1; j <= n; j++)
alpar@1
   193
      {  len = 0;
alpar@1
   194
         for (vij = V_col[j]; vij != NULL; vij = vij->c_next) len++;
alpar@1
   195
         C_len[j] = len;
alpar@1
   196
      }
alpar@1
   197
      /* build linked lists of active columns */
alpar@1
   198
      for (len = 0; len <= n; len++) C_head[len] = 0;
alpar@1
   199
      for (j = 1; j <= n; j++)
alpar@1
   200
      {  len = C_len[j];
alpar@1
   201
         C_prev[j] = 0;
alpar@1
   202
         C_next[j] = C_head[len];
alpar@1
   203
         if (C_next[j] != 0) C_prev[C_next[j]] = j;
alpar@1
   204
         C_head[len] = j;
alpar@1
   205
      }
alpar@1
   206
      return;
alpar@1
   207
}
alpar@1
   208
alpar@1
   209
/*----------------------------------------------------------------------
alpar@1
   210
// find_pivot - choose a pivot element.
alpar@1
   211
//
alpar@1
   212
// This routine chooses a pivot element v[p,q] in the active submatrix
alpar@1
   213
// of matrix U = P*V*Q.
alpar@1
   214
//
alpar@1
   215
// It is assumed that on entry the matrix U has the following partially
alpar@1
   216
// triangularized form:
alpar@1
   217
//
alpar@1
   218
//       1       k         n
alpar@1
   219
//    1  x x x x x x x x x x
alpar@1
   220
//       . x x x x x x x x x
alpar@1
   221
//       . . x x x x x x x x
alpar@1
   222
//       . . . x x x x x x x
alpar@1
   223
//    k  . . . . * * * * * *
alpar@1
   224
//       . . . . * * * * * *
alpar@1
   225
//       . . . . * * * * * *
alpar@1
   226
//       . . . . * * * * * *
alpar@1
   227
//       . . . . * * * * * *
alpar@1
   228
//    n  . . . . * * * * * *
alpar@1
   229
//
alpar@1
   230
// where rows and columns k, k+1, ..., n belong to the active submatrix
alpar@1
   231
// (elements of the active submatrix are marked by '*').
alpar@1
   232
//
alpar@1
   233
// Since the matrix U = P*V*Q is not stored, the routine works with the
alpar@1
   234
// matrix V. It is assumed that the row-wise representation corresponds
alpar@1
   235
// to the matrix V, but the column-wise representation corresponds to
alpar@1
   236
// the active submatrix of the matrix V, i.e. elements of the matrix V,
alpar@1
   237
// which does not belong to the active submatrix, are missing from the
alpar@1
   238
// column linked lists. It is also assumed that each active row of the
alpar@1
   239
// matrix V is in the set R[len], where len is number of non-zeros in
alpar@1
   240
// the row, and each active column of the matrix V is in the set C[len],
alpar@1
   241
// where len is number of non-zeros in the column (in the latter case
alpar@1
   242
// only elements of the active submatrix are counted; such elements are
alpar@1
   243
// marked by '*' on the figure above).
alpar@1
   244
//
alpar@1
   245
// Due to exact arithmetic any non-zero element of the active submatrix
alpar@1
   246
// can be chosen as a pivot. However, to keep sparsity of the matrix V
alpar@1
   247
// the routine uses Markowitz strategy, trying to choose such element
alpar@1
   248
// v[p,q], which has smallest Markowitz cost (nr[p]-1) * (nc[q]-1),
alpar@1
   249
// where nr[p] and nc[q] are the number of non-zero elements, resp., in
alpar@1
   250
// p-th row and in q-th column of the active submatrix.
alpar@1
   251
//
alpar@1
   252
// In order to reduce the search, i.e. not to walk through all elements
alpar@1
   253
// of the active submatrix, the routine exploits a technique proposed by
alpar@1
   254
// I.Duff. This technique is based on using the sets R[len] and C[len]
alpar@1
   255
// of active rows and columns.
alpar@1
   256
//
alpar@1
   257
// On exit the routine returns a pointer to a pivot v[p,q] chosen, or
alpar@1
   258
// NULL, if the active submatrix is empty. */
alpar@1
   259
alpar@1
   260
static LUXELM *find_pivot(LUX *lux, LUXWKA *wka)
alpar@1
   261
{     int n = lux->n;
alpar@1
   262
      LUXELM **V_row = lux->V_row;
alpar@1
   263
      LUXELM **V_col = lux->V_col;
alpar@1
   264
      int *R_len = wka->R_len;
alpar@1
   265
      int *R_head = wka->R_head;
alpar@1
   266
      int *R_next = wka->R_next;
alpar@1
   267
      int *C_len = wka->C_len;
alpar@1
   268
      int *C_head = wka->C_head;
alpar@1
   269
      int *C_next = wka->C_next;
alpar@1
   270
      LUXELM *piv, *some, *vij;
alpar@1
   271
      int i, j, len, min_len, ncand, piv_lim = 5;
alpar@1
   272
      double best, cost;
alpar@1
   273
      /* nothing is chosen so far */
alpar@1
   274
      piv = NULL, best = DBL_MAX, ncand = 0;
alpar@1
   275
      /* if in the active submatrix there is a column that has the only
alpar@1
   276
         non-zero (column singleton), choose it as a pivot */
alpar@1
   277
      j = C_head[1];
alpar@1
   278
      if (j != 0)
alpar@1
   279
      {  xassert(C_len[j] == 1);
alpar@1
   280
         piv = V_col[j];
alpar@1
   281
         xassert(piv != NULL && piv->c_next == NULL);
alpar@1
   282
         goto done;
alpar@1
   283
      }
alpar@1
   284
      /* if in the active submatrix there is a row that has the only
alpar@1
   285
         non-zero (row singleton), choose it as a pivot */
alpar@1
   286
      i = R_head[1];
alpar@1
   287
      if (i != 0)
alpar@1
   288
      {  xassert(R_len[i] == 1);
alpar@1
   289
         piv = V_row[i];
alpar@1
   290
         xassert(piv != NULL && piv->r_next == NULL);
alpar@1
   291
         goto done;
alpar@1
   292
      }
alpar@1
   293
      /* there are no singletons in the active submatrix; walk through
alpar@1
   294
         other non-empty rows and columns */
alpar@1
   295
      for (len = 2; len <= n; len++)
alpar@1
   296
      {  /* consider active columns having len non-zeros */
alpar@1
   297
         for (j = C_head[len]; j != 0; j = C_next[j])
alpar@1
   298
         {  /* j-th column has len non-zeros */
alpar@1
   299
            /* find an element in the row of minimal length */
alpar@1
   300
            some = NULL, min_len = INT_MAX;
alpar@1
   301
            for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
alpar@1
   302
            {  if (min_len > R_len[vij->i])
alpar@1
   303
                  some = vij, min_len = R_len[vij->i];
alpar@1
   304
               /* if Markowitz cost of this element is not greater than
alpar@1
   305
                  (len-1)**2, it can be chosen right now; this heuristic
alpar@1
   306
                  reduces the search and works well in many cases */
alpar@1
   307
               if (min_len <= len)
alpar@1
   308
               {  piv = some;
alpar@1
   309
                  goto done;
alpar@1
   310
               }
alpar@1
   311
            }
alpar@1
   312
            /* j-th column has been scanned */
alpar@1
   313
            /* the minimal element found is a next pivot candidate */
alpar@1
   314
            xassert(some != NULL);
alpar@1
   315
            ncand++;
alpar@1
   316
            /* compute its Markowitz cost */
alpar@1
   317
            cost = (double)(min_len - 1) * (double)(len - 1);
alpar@1
   318
            /* choose between the current candidate and this element */
alpar@1
   319
            if (cost < best) piv = some, best = cost;
alpar@1
   320
            /* if piv_lim candidates have been considered, there is a
alpar@1
   321
               doubt that a much better candidate exists; therefore it
alpar@1
   322
               is the time to terminate the search */
alpar@1
   323
            if (ncand == piv_lim) goto done;
alpar@1
   324
         }
alpar@1
   325
         /* now consider active rows having len non-zeros */
alpar@1
   326
         for (i = R_head[len]; i != 0; i = R_next[i])
alpar@1
   327
         {  /* i-th row has len non-zeros */
alpar@1
   328
            /* find an element in the column of minimal length */
alpar@1
   329
            some = NULL, min_len = INT_MAX;
alpar@1
   330
            for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
alpar@1
   331
            {  if (min_len > C_len[vij->j])
alpar@1
   332
                  some = vij, min_len = C_len[vij->j];
alpar@1
   333
               /* if Markowitz cost of this element is not greater than
alpar@1
   334
                  (len-1)**2, it can be chosen right now; this heuristic
alpar@1
   335
                  reduces the search and works well in many cases */
alpar@1
   336
               if (min_len <= len)
alpar@1
   337
               {  piv = some;
alpar@1
   338
                  goto done;
alpar@1
   339
               }
alpar@1
   340
            }
alpar@1
   341
            /* i-th row has been scanned */
alpar@1
   342
            /* the minimal element found is a next pivot candidate */
alpar@1
   343
            xassert(some != NULL);
alpar@1
   344
            ncand++;
alpar@1
   345
            /* compute its Markowitz cost */
alpar@1
   346
            cost = (double)(len - 1) * (double)(min_len - 1);
alpar@1
   347
            /* choose between the current candidate and this element */
alpar@1
   348
            if (cost < best) piv = some, best = cost;
alpar@1
   349
            /* if piv_lim candidates have been considered, there is a
alpar@1
   350
               doubt that a much better candidate exists; therefore it
alpar@1
   351
               is the time to terminate the search */
alpar@1
   352
            if (ncand == piv_lim) goto done;
alpar@1
   353
         }
alpar@1
   354
      }
alpar@1
   355
done: /* bring the pivot v[p,q] to the factorizing routine */
alpar@1
   356
      return piv;
alpar@1
   357
}
alpar@1
   358
alpar@1
   359
/*----------------------------------------------------------------------
alpar@1
   360
// eliminate - perform gaussian elimination.
alpar@1
   361
//
alpar@1
   362
// This routine performs elementary gaussian transformations in order
alpar@1
   363
// to eliminate subdiagonal elements in the k-th column of the matrix
alpar@1
   364
// U = P*V*Q using the pivot element u[k,k], where k is the number of
alpar@1
   365
// the current elimination step.
alpar@1
   366
//
alpar@1
   367
// The parameter piv specifies the pivot element v[p,q] = u[k,k].
alpar@1
   368
//
alpar@1
   369
// Each time when the routine applies the elementary transformation to
alpar@1
   370
// a non-pivot row of the matrix V, it stores the corresponding element
alpar@1
   371
// to the matrix F in order to keep the main equality A = F*V.
alpar@1
   372
//
alpar@1
   373
// The routine assumes that on entry the matrices L = P*F*inv(P) and
alpar@1
   374
// U = P*V*Q are the following:
alpar@1
   375
//
alpar@1
   376
//       1       k                  1       k         n
alpar@1
   377
//    1  1 . . . . . . . . .     1  x x x x x x x x x x
alpar@1
   378
//       x 1 . . . . . . . .        . x x x x x x x x x
alpar@1
   379
//       x x 1 . . . . . . .        . . x x x x x x x x
alpar@1
   380
//       x x x 1 . . . . . .        . . . x x x x x x x
alpar@1
   381
//    k  x x x x 1 . . . . .     k  . . . . * * * * * *
alpar@1
   382
//       x x x x _ 1 . . . .        . . . . # * * * * *
alpar@1
   383
//       x x x x _ . 1 . . .        . . . . # * * * * *
alpar@1
   384
//       x x x x _ . . 1 . .        . . . . # * * * * *
alpar@1
   385
//       x x x x _ . . . 1 .        . . . . # * * * * *
alpar@1
   386
//    n  x x x x _ . . . . 1     n  . . . . # * * * * *
alpar@1
   387
//
alpar@1
   388
//            matrix L                   matrix U
alpar@1
   389
//
alpar@1
   390
// where rows and columns of the matrix U with numbers k, k+1, ..., n
alpar@1
   391
// form the active submatrix (eliminated elements are marked by '#' and
alpar@1
   392
// other elements of the active submatrix are marked by '*'). Note that
alpar@1
   393
// each eliminated non-zero element u[i,k] of the matrix U gives the
alpar@1
   394
// corresponding element l[i,k] of the matrix L (marked by '_').
alpar@1
   395
//
alpar@1
   396
// Actually all operations are performed on the matrix V. Should note
alpar@1
   397
// that the row-wise representation corresponds to the matrix V, but the
alpar@1
   398
// column-wise representation corresponds to the active submatrix of the
alpar@1
   399
// matrix V, i.e. elements of the matrix V, which doesn't belong to the
alpar@1
   400
// active submatrix, are missing from the column linked lists.
alpar@1
   401
//
alpar@1
   402
// Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
alpar@1
   403
// elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
alpar@1
   404
// the following elementary gaussian transformations:
alpar@1
   405
//
alpar@1
   406
//    (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
alpar@1
   407
//
alpar@1
   408
// where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
alpar@1
   409
//
alpar@1
   410
// Additionally, in order to keep the main equality A = F*V, each time
alpar@1
   411
// when the routine applies the transformation to i-th row of the matrix
alpar@1
   412
// V, it also adds f[i,p] as a new element to the matrix F.
alpar@1
   413
//
alpar@1
   414
// IMPORTANT: On entry the working arrays flag and work should contain
alpar@1
   415
// zeros. This status is provided by the routine on exit. */
alpar@1
   416
alpar@1
   417
static void eliminate(LUX *lux, LUXWKA *wka, LUXELM *piv, int flag[],
alpar@1
   418
      mpq_t work[])
alpar@1
   419
{     DMP *pool = lux->pool;
alpar@1
   420
      LUXELM **F_row = lux->F_row;
alpar@1
   421
      LUXELM **F_col = lux->F_col;
alpar@1
   422
      mpq_t *V_piv = lux->V_piv;
alpar@1
   423
      LUXELM **V_row = lux->V_row;
alpar@1
   424
      LUXELM **V_col = lux->V_col;
alpar@1
   425
      int *R_len = wka->R_len;
alpar@1
   426
      int *R_head = wka->R_head;
alpar@1
   427
      int *R_prev = wka->R_prev;
alpar@1
   428
      int *R_next = wka->R_next;
alpar@1
   429
      int *C_len = wka->C_len;
alpar@1
   430
      int *C_head = wka->C_head;
alpar@1
   431
      int *C_prev = wka->C_prev;
alpar@1
   432
      int *C_next = wka->C_next;
alpar@1
   433
      LUXELM *fip, *vij, *vpj, *viq, *next;
alpar@1
   434
      mpq_t temp;
alpar@1
   435
      int i, j, p, q;
alpar@1
   436
      mpq_init(temp);
alpar@1
   437
      /* determine row and column indices of the pivot v[p,q] */
alpar@1
   438
      xassert(piv != NULL);
alpar@1
   439
      p = piv->i, q = piv->j;
alpar@1
   440
      /* remove p-th (pivot) row from the active set; it will never
alpar@1
   441
         return there */
alpar@1
   442
      if (R_prev[p] == 0)
alpar@1
   443
         R_head[R_len[p]] = R_next[p];
alpar@1
   444
      else
alpar@1
   445
         R_next[R_prev[p]] = R_next[p];
alpar@1
   446
      if (R_next[p] == 0)
alpar@1
   447
         ;
alpar@1
   448
      else
alpar@1
   449
         R_prev[R_next[p]] = R_prev[p];
alpar@1
   450
      /* remove q-th (pivot) column from the active set; it will never
alpar@1
   451
         return there */
alpar@1
   452
      if (C_prev[q] == 0)
alpar@1
   453
         C_head[C_len[q]] = C_next[q];
alpar@1
   454
      else
alpar@1
   455
         C_next[C_prev[q]] = C_next[q];
alpar@1
   456
      if (C_next[q] == 0)
alpar@1
   457
         ;
alpar@1
   458
      else
alpar@1
   459
         C_prev[C_next[q]] = C_prev[q];
alpar@1
   460
      /* store the pivot value in a separate array */
alpar@1
   461
      mpq_set(V_piv[p], piv->val);
alpar@1
   462
      /* remove the pivot from p-th row */
alpar@1
   463
      if (piv->r_prev == NULL)
alpar@1
   464
         V_row[p] = piv->r_next;
alpar@1
   465
      else
alpar@1
   466
         piv->r_prev->r_next = piv->r_next;
alpar@1
   467
      if (piv->r_next == NULL)
alpar@1
   468
         ;
alpar@1
   469
      else
alpar@1
   470
         piv->r_next->r_prev = piv->r_prev;
alpar@1
   471
      R_len[p]--;
alpar@1
   472
      /* remove the pivot from q-th column */
alpar@1
   473
      if (piv->c_prev == NULL)
alpar@1
   474
         V_col[q] = piv->c_next;
alpar@1
   475
      else
alpar@1
   476
         piv->c_prev->c_next = piv->c_next;
alpar@1
   477
      if (piv->c_next == NULL)
alpar@1
   478
         ;
alpar@1
   479
      else
alpar@1
   480
         piv->c_next->c_prev = piv->c_prev;
alpar@1
   481
      C_len[q]--;
alpar@1
   482
      /* free the space occupied by the pivot */
alpar@1
   483
      mpq_clear(piv->val);
alpar@1
   484
      dmp_free_atom(pool, piv, sizeof(LUXELM));
alpar@1
   485
      /* walk through p-th (pivot) row, which already does not contain
alpar@1
   486
         the pivot v[p,q], and do the following... */
alpar@1
   487
      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
alpar@1
   488
      {  /* get column index of v[p,j] */
alpar@1
   489
         j = vpj->j;
alpar@1
   490
         /* store v[p,j] in the working array */
alpar@1
   491
         flag[j] = 1;
alpar@1
   492
         mpq_set(work[j], vpj->val);
alpar@1
   493
         /* remove j-th column from the active set; it will return there
alpar@1
   494
            later with a new length */
alpar@1
   495
         if (C_prev[j] == 0)
alpar@1
   496
            C_head[C_len[j]] = C_next[j];
alpar@1
   497
         else
alpar@1
   498
            C_next[C_prev[j]] = C_next[j];
alpar@1
   499
         if (C_next[j] == 0)
alpar@1
   500
            ;
alpar@1
   501
         else
alpar@1
   502
            C_prev[C_next[j]] = C_prev[j];
alpar@1
   503
         /* v[p,j] leaves the active submatrix, so remove it from j-th
alpar@1
   504
            column; however, v[p,j] is kept in p-th row */
alpar@1
   505
         if (vpj->c_prev == NULL)
alpar@1
   506
            V_col[j] = vpj->c_next;
alpar@1
   507
         else
alpar@1
   508
            vpj->c_prev->c_next = vpj->c_next;
alpar@1
   509
         if (vpj->c_next == NULL)
alpar@1
   510
            ;
alpar@1
   511
         else
alpar@1
   512
            vpj->c_next->c_prev = vpj->c_prev;
alpar@1
   513
         C_len[j]--;
alpar@1
   514
      }
alpar@1
   515
      /* now walk through q-th (pivot) column, which already does not
alpar@1
   516
         contain the pivot v[p,q], and perform gaussian elimination */
alpar@1
   517
      while (V_col[q] != NULL)
alpar@1
   518
      {  /* element v[i,q] has to be eliminated */
alpar@1
   519
         viq = V_col[q];
alpar@1
   520
         /* get row index of v[i,q] */
alpar@1
   521
         i = viq->i;
alpar@1
   522
         /* remove i-th row from the active set; later it will return
alpar@1
   523
            there with a new length */
alpar@1
   524
         if (R_prev[i] == 0)
alpar@1
   525
            R_head[R_len[i]] = R_next[i];
alpar@1
   526
         else
alpar@1
   527
            R_next[R_prev[i]] = R_next[i];
alpar@1
   528
         if (R_next[i] == 0)
alpar@1
   529
            ;
alpar@1
   530
         else
alpar@1
   531
            R_prev[R_next[i]] = R_prev[i];
alpar@1
   532
         /* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] and
alpar@1
   533
            store it in the matrix F */
alpar@1
   534
         fip = dmp_get_atom(pool, sizeof(LUXELM));
alpar@1
   535
         fip->i = i, fip->j = p;
alpar@1
   536
         mpq_init(fip->val);
alpar@1
   537
         mpq_div(fip->val, viq->val, V_piv[p]);
alpar@1
   538
         fip->r_prev = NULL;
alpar@1
   539
         fip->r_next = F_row[i];
alpar@1
   540
         fip->c_prev = NULL;
alpar@1
   541
         fip->c_next = F_col[p];
alpar@1
   542
         if (fip->r_next != NULL) fip->r_next->r_prev = fip;
alpar@1
   543
         if (fip->c_next != NULL) fip->c_next->c_prev = fip;
alpar@1
   544
         F_row[i] = F_col[p] = fip;
alpar@1
   545
         /* v[i,q] has to be eliminated, so remove it from i-th row */
alpar@1
   546
         if (viq->r_prev == NULL)
alpar@1
   547
            V_row[i] = viq->r_next;
alpar@1
   548
         else
alpar@1
   549
            viq->r_prev->r_next = viq->r_next;
alpar@1
   550
         if (viq->r_next == NULL)
alpar@1
   551
            ;
alpar@1
   552
         else
alpar@1
   553
            viq->r_next->r_prev = viq->r_prev;
alpar@1
   554
         R_len[i]--;
alpar@1
   555
         /* and also from q-th column */
alpar@1
   556
         V_col[q] = viq->c_next;
alpar@1
   557
         C_len[q]--;
alpar@1
   558
         /* free the space occupied by v[i,q] */
alpar@1
   559
         mpq_clear(viq->val);
alpar@1
   560
         dmp_free_atom(pool, viq, sizeof(LUXELM));
alpar@1
   561
         /* perform gaussian transformation:
alpar@1
   562
            (i-th row) := (i-th row) - f[i,p] * (p-th row)
alpar@1
   563
            note that now p-th row, which is in the working array,
alpar@1
   564
            does not contain the pivot v[p,q], and i-th row does not
alpar@1
   565
            contain the element v[i,q] to be eliminated */
alpar@1
   566
         /* walk through i-th row and transform existing non-zero
alpar@1
   567
            elements */
alpar@1
   568
         for (vij = V_row[i]; vij != NULL; vij = next)
alpar@1
   569
         {  next = vij->r_next;
alpar@1
   570
            /* get column index of v[i,j] */
alpar@1
   571
            j = vij->j;
alpar@1
   572
            /* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
alpar@1
   573
            if (flag[j])
alpar@1
   574
            {  /* v[p,j] != 0 */
alpar@1
   575
               flag[j] = 0;
alpar@1
   576
               mpq_mul(temp, fip->val, work[j]);
alpar@1
   577
               mpq_sub(vij->val, vij->val, temp);
alpar@1
   578
               if (mpq_sgn(vij->val) == 0)
alpar@1
   579
               {  /* new v[i,j] is zero, so remove it from the active
alpar@1
   580
                     submatrix */
alpar@1
   581
                  /* remove v[i,j] from i-th row */
alpar@1
   582
                  if (vij->r_prev == NULL)
alpar@1
   583
                     V_row[i] = vij->r_next;
alpar@1
   584
                  else
alpar@1
   585
                     vij->r_prev->r_next = vij->r_next;
alpar@1
   586
                  if (vij->r_next == NULL)
alpar@1
   587
                     ;
alpar@1
   588
                  else
alpar@1
   589
                     vij->r_next->r_prev = vij->r_prev;
alpar@1
   590
                  R_len[i]--;
alpar@1
   591
                  /* remove v[i,j] from j-th column */
alpar@1
   592
                  if (vij->c_prev == NULL)
alpar@1
   593
                     V_col[j] = vij->c_next;
alpar@1
   594
                  else
alpar@1
   595
                     vij->c_prev->c_next = vij->c_next;
alpar@1
   596
                  if (vij->c_next == NULL)
alpar@1
   597
                     ;
alpar@1
   598
                  else
alpar@1
   599
                     vij->c_next->c_prev = vij->c_prev;
alpar@1
   600
                  C_len[j]--;
alpar@1
   601
                  /* free the space occupied by v[i,j] */
alpar@1
   602
                  mpq_clear(vij->val);
alpar@1
   603
                  dmp_free_atom(pool, vij, sizeof(LUXELM));
alpar@1
   604
               }
alpar@1
   605
            }
alpar@1
   606
         }
alpar@1
   607
         /* now flag is the pattern of the set v[p,*] \ v[i,*] */
alpar@1
   608
         /* walk through p-th (pivot) row and create new elements in
alpar@1
   609
            i-th row, which appear due to fill-in */
alpar@1
   610
         for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
alpar@1
   611
         {  j = vpj->j;
alpar@1
   612
            if (flag[j])
alpar@1
   613
            {  /* create new non-zero v[i,j] = 0 - f[i,p] * v[p,j] and
alpar@1
   614
                  add it to i-th row and j-th column */
alpar@1
   615
               vij = dmp_get_atom(pool, sizeof(LUXELM));
alpar@1
   616
               vij->i = i, vij->j = j;
alpar@1
   617
               mpq_init(vij->val);
alpar@1
   618
               mpq_mul(vij->val, fip->val, work[j]);
alpar@1
   619
               mpq_neg(vij->val, vij->val);
alpar@1
   620
               vij->r_prev = NULL;
alpar@1
   621
               vij->r_next = V_row[i];
alpar@1
   622
               vij->c_prev = NULL;
alpar@1
   623
               vij->c_next = V_col[j];
alpar@1
   624
               if (vij->r_next != NULL) vij->r_next->r_prev = vij;
alpar@1
   625
               if (vij->c_next != NULL) vij->c_next->c_prev = vij;
alpar@1
   626
               V_row[i] = V_col[j] = vij;
alpar@1
   627
               R_len[i]++, C_len[j]++;
alpar@1
   628
            }
alpar@1
   629
            else
alpar@1
   630
            {  /* there is no fill-in, because v[i,j] already exists in
alpar@1
   631
                  i-th row; restore the flag, which was reset before */
alpar@1
   632
               flag[j] = 1;
alpar@1
   633
            }
alpar@1
   634
         }
alpar@1
   635
         /* now i-th row has been completely transformed and can return
alpar@1
   636
            to the active set with a new length */
alpar@1
   637
         R_prev[i] = 0;
alpar@1
   638
         R_next[i] = R_head[R_len[i]];
alpar@1
   639
         if (R_next[i] != 0) R_prev[R_next[i]] = i;
alpar@1
   640
         R_head[R_len[i]] = i;
alpar@1
   641
      }
alpar@1
   642
      /* at this point q-th (pivot) column must be empty */
alpar@1
   643
      xassert(C_len[q] == 0);
alpar@1
   644
      /* walk through p-th (pivot) row again and do the following... */
alpar@1
   645
      for (vpj = V_row[p]; vpj != NULL; vpj = vpj->r_next)
alpar@1
   646
      {  /* get column index of v[p,j] */
alpar@1
   647
         j = vpj->j;
alpar@1
   648
         /* erase v[p,j] from the working array */
alpar@1
   649
         flag[j] = 0;
alpar@1
   650
         mpq_set_si(work[j], 0, 1);
alpar@1
   651
         /* now j-th column has been completely transformed, so it can
alpar@1
   652
            return to the active list with a new length */
alpar@1
   653
         C_prev[j] = 0;
alpar@1
   654
         C_next[j] = C_head[C_len[j]];
alpar@1
   655
         if (C_next[j] != 0) C_prev[C_next[j]] = j;
alpar@1
   656
         C_head[C_len[j]] = j;
alpar@1
   657
      }
alpar@1
   658
      mpq_clear(temp);
alpar@1
   659
      /* return to the factorizing routine */
alpar@1
   660
      return;
alpar@1
   661
}
alpar@1
   662
alpar@1
   663
/*----------------------------------------------------------------------
alpar@1
   664
// lux_decomp - compute LU-factorization.
alpar@1
   665
//
alpar@1
   666
// SYNOPSIS
alpar@1
   667
//
alpar@1
   668
// #include "glplux.h"
alpar@1
   669
// int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
alpar@1
   670
//    mpq_t val[]), void *info);
alpar@1
   671
//
alpar@1
   672
// DESCRIPTION
alpar@1
   673
//
alpar@1
   674
// The routine lux_decomp computes LU-factorization of a given square
alpar@1
   675
// matrix A.
alpar@1
   676
//
alpar@1
   677
// The parameter lux specifies LU-factorization data structure built by
alpar@1
   678
// means of the routine lux_create.
alpar@1
   679
//
alpar@1
   680
// The formal routine col specifies the original matrix A. In order to
alpar@1
   681
// obtain j-th column of the matrix A the routine lux_decomp calls the
alpar@1
   682
// routine col with the parameter j (1 <= j <= n, where n is the order
alpar@1
   683
// of A). In response the routine col should store row indices and
alpar@1
   684
// numerical values of non-zero elements of j-th column of A to the
alpar@1
   685
// locations ind[1], ..., ind[len] and val[1], ..., val[len], resp.,
alpar@1
   686
// where len is the number of non-zeros in j-th column, which should be
alpar@1
   687
// returned on exit. Neiter zero nor duplicate elements are allowed.
alpar@1
   688
//
alpar@1
   689
// The parameter info is a transit pointer passed to the formal routine
alpar@1
   690
// col; it can be used for various purposes.
alpar@1
   691
//
alpar@1
   692
// RETURNS
alpar@1
   693
//
alpar@1
   694
// The routine lux_decomp returns the singularity flag. Zero flag means
alpar@1
   695
// that the original matrix A is non-singular while non-zero flag means
alpar@1
   696
// that A is (exactly!) singular.
alpar@1
   697
//
alpar@1
   698
// Note that LU-factorization is valid in both cases, however, in case
alpar@1
   699
// of singularity some rows of the matrix V (including pivot elements)
alpar@1
   700
// will be empty.
alpar@1
   701
//
alpar@1
   702
// REPAIRING SINGULAR MATRIX
alpar@1
   703
//
alpar@1
   704
// If the routine lux_decomp returns non-zero flag, it provides all
alpar@1
   705
// necessary information that can be used for "repairing" the matrix A,
alpar@1
   706
// where "repairing" means replacing linearly dependent columns of the
alpar@1
   707
// matrix A by appropriate columns of the unity matrix. This feature is
alpar@1
   708
// needed when the routine lux_decomp is used for reinverting the basis
alpar@1
   709
// matrix within the simplex method procedure.
alpar@1
   710
//
alpar@1
   711
// On exit linearly dependent columns of the matrix U have the numbers
alpar@1
   712
// rank+1, rank+2, ..., n, where rank is the exact rank of the matrix A
alpar@1
   713
// stored by the routine to the member lux->rank. The correspondence
alpar@1
   714
// between columns of A and U is the same as between columns of V and U.
alpar@1
   715
// Thus, linearly dependent columns of the matrix A have the numbers
alpar@1
   716
// Q_col[rank+1], Q_col[rank+2], ..., Q_col[n], where Q_col is an array
alpar@1
   717
// representing the permutation matrix Q in column-like format. It is
alpar@1
   718
// understood that each j-th linearly dependent column of the matrix U
alpar@1
   719
// should be replaced by the unity vector, where all elements are zero
alpar@1
   720
// except the unity diagonal element u[j,j]. On the other hand j-th row
alpar@1
   721
// of the matrix U corresponds to the row of the matrix V (and therefore
alpar@1
   722
// of the matrix A) with the number P_row[j], where P_row is an array
alpar@1
   723
// representing the permutation matrix P in row-like format. Thus, each
alpar@1
   724
// j-th linearly dependent column of the matrix U should be replaced by
alpar@1
   725
// a column of the unity matrix with the number P_row[j].
alpar@1
   726
//
alpar@1
   727
// The code that repairs the matrix A may look like follows:
alpar@1
   728
//
alpar@1
   729
//    for (j = rank+1; j <= n; j++)
alpar@1
   730
//    {  replace column Q_col[j] of the matrix A by column P_row[j] of
alpar@1
   731
//       the unity matrix;
alpar@1
   732
//    }
alpar@1
   733
//
alpar@1
   734
// where rank, P_row, and Q_col are members of the structure LUX. */
alpar@1
   735
alpar@1
   736
int lux_decomp(LUX *lux, int (*col)(void *info, int j, int ind[],
alpar@1
   737
      mpq_t val[]), void *info)
alpar@1
   738
{     int n = lux->n;
alpar@1
   739
      LUXELM **V_row = lux->V_row;
alpar@1
   740
      LUXELM **V_col = lux->V_col;
alpar@1
   741
      int *P_row = lux->P_row;
alpar@1
   742
      int *P_col = lux->P_col;
alpar@1
   743
      int *Q_row = lux->Q_row;
alpar@1
   744
      int *Q_col = lux->Q_col;
alpar@1
   745
      LUXELM *piv, *vij;
alpar@1
   746
      LUXWKA *wka;
alpar@1
   747
      int i, j, k, p, q, t, *flag;
alpar@1
   748
      mpq_t *work;
alpar@1
   749
      /* allocate working area */
alpar@1
   750
      wka = xmalloc(sizeof(LUXWKA));
alpar@1
   751
      wka->R_len = xcalloc(1+n, sizeof(int));
alpar@1
   752
      wka->R_head = xcalloc(1+n, sizeof(int));
alpar@1
   753
      wka->R_prev = xcalloc(1+n, sizeof(int));
alpar@1
   754
      wka->R_next = xcalloc(1+n, sizeof(int));
alpar@1
   755
      wka->C_len = xcalloc(1+n, sizeof(int));
alpar@1
   756
      wka->C_head = xcalloc(1+n, sizeof(int));
alpar@1
   757
      wka->C_prev = xcalloc(1+n, sizeof(int));
alpar@1
   758
      wka->C_next = xcalloc(1+n, sizeof(int));
alpar@1
   759
      /* initialize LU-factorization data structures */
alpar@1
   760
      initialize(lux, col, info, wka);
alpar@1
   761
      /* allocate working arrays */
alpar@1
   762
      flag = xcalloc(1+n, sizeof(int));
alpar@1
   763
      work = xcalloc(1+n, sizeof(mpq_t));
alpar@1
   764
      for (k = 1; k <= n; k++)
alpar@1
   765
      {  flag[k] = 0;
alpar@1
   766
         mpq_init(work[k]);
alpar@1
   767
      }
alpar@1
   768
      /* main elimination loop */
alpar@1
   769
      for (k = 1; k <= n; k++)
alpar@1
   770
      {  /* choose a pivot element v[p,q] */
alpar@1
   771
         piv = find_pivot(lux, wka);
alpar@1
   772
         if (piv == NULL)
alpar@1
   773
         {  /* no pivot can be chosen, because the active submatrix is
alpar@1
   774
               empty */
alpar@1
   775
            break;
alpar@1
   776
         }
alpar@1
   777
         /* determine row and column indices of the pivot element */
alpar@1
   778
         p = piv->i, q = piv->j;
alpar@1
   779
         /* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
alpar@1
   780
            rows and k-th and j'-th columns of the matrix U = P*V*Q to
alpar@1
   781
            move the element u[i',j'] to the position u[k,k] */
alpar@1
   782
         i = P_col[p], j = Q_row[q];
alpar@1
   783
         xassert(k <= i && i <= n && k <= j && j <= n);
alpar@1
   784
         /* permute k-th and i-th rows of the matrix U */
alpar@1
   785
         t = P_row[k];
alpar@1
   786
         P_row[i] = t, P_col[t] = i;
alpar@1
   787
         P_row[k] = p, P_col[p] = k;
alpar@1
   788
         /* permute k-th and j-th columns of the matrix U */
alpar@1
   789
         t = Q_col[k];
alpar@1
   790
         Q_col[j] = t, Q_row[t] = j;
alpar@1
   791
         Q_col[k] = q, Q_row[q] = k;
alpar@1
   792
         /* eliminate subdiagonal elements of k-th column of the matrix
alpar@1
   793
            U = P*V*Q using the pivot element u[k,k] = v[p,q] */
alpar@1
   794
         eliminate(lux, wka, piv, flag, work);
alpar@1
   795
      }
alpar@1
   796
      /* determine the rank of A (and V) */
alpar@1
   797
      lux->rank = k - 1;
alpar@1
   798
      /* free working arrays */
alpar@1
   799
      xfree(flag);
alpar@1
   800
      for (k = 1; k <= n; k++) mpq_clear(work[k]);
alpar@1
   801
      xfree(work);
alpar@1
   802
      /* build column lists of the matrix V using its row lists */
alpar@1
   803
      for (j = 1; j <= n; j++)
alpar@1
   804
         xassert(V_col[j] == NULL);
alpar@1
   805
      for (i = 1; i <= n; i++)
alpar@1
   806
      {  for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
alpar@1
   807
         {  j = vij->j;
alpar@1
   808
            vij->c_prev = NULL;
alpar@1
   809
            vij->c_next = V_col[j];
alpar@1
   810
            if (vij->c_next != NULL) vij->c_next->c_prev = vij;
alpar@1
   811
            V_col[j] = vij;
alpar@1
   812
         }
alpar@1
   813
      }
alpar@1
   814
      /* free working area */
alpar@1
   815
      xfree(wka->R_len);
alpar@1
   816
      xfree(wka->R_head);
alpar@1
   817
      xfree(wka->R_prev);
alpar@1
   818
      xfree(wka->R_next);
alpar@1
   819
      xfree(wka->C_len);
alpar@1
   820
      xfree(wka->C_head);
alpar@1
   821
      xfree(wka->C_prev);
alpar@1
   822
      xfree(wka->C_next);
alpar@1
   823
      xfree(wka);
alpar@1
   824
      /* return to the calling program */
alpar@1
   825
      return (lux->rank < n);
alpar@1
   826
}
alpar@1
   827
alpar@1
   828
/*----------------------------------------------------------------------
alpar@1
   829
// lux_f_solve - solve system F*x = b or F'*x = b.
alpar@1
   830
//
alpar@1
   831
// SYNOPSIS
alpar@1
   832
//
alpar@1
   833
// #include "glplux.h"
alpar@1
   834
// void lux_f_solve(LUX *lux, int tr, mpq_t x[]);
alpar@1
   835
//
alpar@1
   836
// DESCRIPTION
alpar@1
   837
//
alpar@1
   838
// The routine lux_f_solve solves either the system F*x = b (if the
alpar@1
   839
// flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
alpar@1
   840
// where the matrix F is a component of LU-factorization specified by
alpar@1
   841
// the parameter lux, F' is a matrix transposed to F.
alpar@1
   842
//
alpar@1
   843
// On entry the array x should contain elements of the right-hand side
alpar@1
   844
// vector b in locations x[1], ..., x[n], where n is the order of the
alpar@1
   845
// matrix F. On exit this array will contain elements of the solution
alpar@1
   846
// vector x in the same locations. */
alpar@1
   847
alpar@1
   848
void lux_f_solve(LUX *lux, int tr, mpq_t x[])
alpar@1
   849
{     int n = lux->n;
alpar@1
   850
      LUXELM **F_row = lux->F_row;
alpar@1
   851
      LUXELM **F_col = lux->F_col;
alpar@1
   852
      int *P_row = lux->P_row;
alpar@1
   853
      LUXELM *fik, *fkj;
alpar@1
   854
      int i, j, k;
alpar@1
   855
      mpq_t temp;
alpar@1
   856
      mpq_init(temp);
alpar@1
   857
      if (!tr)
alpar@1
   858
      {  /* solve the system F*x = b */
alpar@1
   859
         for (j = 1; j <= n; j++)
alpar@1
   860
         {  k = P_row[j];
alpar@1
   861
            if (mpq_sgn(x[k]) != 0)
alpar@1
   862
            {  for (fik = F_col[k]; fik != NULL; fik = fik->c_next)
alpar@1
   863
               {  mpq_mul(temp, fik->val, x[k]);
alpar@1
   864
                  mpq_sub(x[fik->i], x[fik->i], temp);
alpar@1
   865
               }
alpar@1
   866
            }
alpar@1
   867
         }
alpar@1
   868
      }
alpar@1
   869
      else
alpar@1
   870
      {  /* solve the system F'*x = b */
alpar@1
   871
         for (i = n; i >= 1; i--)
alpar@1
   872
         {  k = P_row[i];
alpar@1
   873
            if (mpq_sgn(x[k]) != 0)
alpar@1
   874
            {  for (fkj = F_row[k]; fkj != NULL; fkj = fkj->r_next)
alpar@1
   875
               {  mpq_mul(temp, fkj->val, x[k]);
alpar@1
   876
                  mpq_sub(x[fkj->j], x[fkj->j], temp);
alpar@1
   877
               }
alpar@1
   878
            }
alpar@1
   879
         }
alpar@1
   880
      }
alpar@1
   881
      mpq_clear(temp);
alpar@1
   882
      return;
alpar@1
   883
}
alpar@1
   884
alpar@1
   885
/*----------------------------------------------------------------------
alpar@1
   886
// lux_v_solve - solve system V*x = b or V'*x = b.
alpar@1
   887
//
alpar@1
   888
// SYNOPSIS
alpar@1
   889
//
alpar@1
   890
// #include "glplux.h"
alpar@1
   891
// void lux_v_solve(LUX *lux, int tr, double x[]);
alpar@1
   892
//
alpar@1
   893
// DESCRIPTION
alpar@1
   894
//
alpar@1
   895
// The routine lux_v_solve solves either the system V*x = b (if the
alpar@1
   896
// flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
alpar@1
   897
// where the matrix V is a component of LU-factorization specified by
alpar@1
   898
// the parameter lux, V' is a matrix transposed to V.
alpar@1
   899
//
alpar@1
   900
// On entry the array x should contain elements of the right-hand side
alpar@1
   901
// vector b in locations x[1], ..., x[n], where n is the order of the
alpar@1
   902
// matrix V. On exit this array will contain elements of the solution
alpar@1
   903
// vector x in the same locations. */
alpar@1
   904
alpar@1
   905
void lux_v_solve(LUX *lux, int tr, mpq_t x[])
alpar@1
   906
{     int n = lux->n;
alpar@1
   907
      mpq_t *V_piv = lux->V_piv;
alpar@1
   908
      LUXELM **V_row = lux->V_row;
alpar@1
   909
      LUXELM **V_col = lux->V_col;
alpar@1
   910
      int *P_row = lux->P_row;
alpar@1
   911
      int *Q_col = lux->Q_col;
alpar@1
   912
      LUXELM *vij;
alpar@1
   913
      int i, j, k;
alpar@1
   914
      mpq_t *b, temp;
alpar@1
   915
      b = xcalloc(1+n, sizeof(mpq_t));
alpar@1
   916
      for (k = 1; k <= n; k++)
alpar@1
   917
         mpq_init(b[k]), mpq_set(b[k], x[k]), mpq_set_si(x[k], 0, 1);
alpar@1
   918
      mpq_init(temp);
alpar@1
   919
      if (!tr)
alpar@1
   920
      {  /* solve the system V*x = b */
alpar@1
   921
         for (k = n; k >= 1; k--)
alpar@1
   922
         {  i = P_row[k], j = Q_col[k];
alpar@1
   923
            if (mpq_sgn(b[i]) != 0)
alpar@1
   924
            {  mpq_set(x[j], b[i]);
alpar@1
   925
               mpq_div(x[j], x[j], V_piv[i]);
alpar@1
   926
               for (vij = V_col[j]; vij != NULL; vij = vij->c_next)
alpar@1
   927
               {  mpq_mul(temp, vij->val, x[j]);
alpar@1
   928
                  mpq_sub(b[vij->i], b[vij->i], temp);
alpar@1
   929
               }
alpar@1
   930
            }
alpar@1
   931
         }
alpar@1
   932
      }
alpar@1
   933
      else
alpar@1
   934
      {  /* solve the system V'*x = b */
alpar@1
   935
         for (k = 1; k <= n; k++)
alpar@1
   936
         {  i = P_row[k], j = Q_col[k];
alpar@1
   937
            if (mpq_sgn(b[j]) != 0)
alpar@1
   938
            {  mpq_set(x[i], b[j]);
alpar@1
   939
               mpq_div(x[i], x[i], V_piv[i]);
alpar@1
   940
               for (vij = V_row[i]; vij != NULL; vij = vij->r_next)
alpar@1
   941
               {  mpq_mul(temp, vij->val, x[i]);
alpar@1
   942
                  mpq_sub(b[vij->j], b[vij->j], temp);
alpar@1
   943
               }
alpar@1
   944
            }
alpar@1
   945
         }
alpar@1
   946
      }
alpar@1
   947
      for (k = 1; k <= n; k++) mpq_clear(b[k]);
alpar@1
   948
      mpq_clear(temp);
alpar@1
   949
      xfree(b);
alpar@1
   950
      return;
alpar@1
   951
}
alpar@1
   952
alpar@1
   953
/*----------------------------------------------------------------------
alpar@1
   954
// lux_solve - solve system A*x = b or A'*x = b.
alpar@1
   955
//
alpar@1
   956
// SYNOPSIS
alpar@1
   957
//
alpar@1
   958
// #include "glplux.h"
alpar@1
   959
// void lux_solve(LUX *lux, int tr, mpq_t x[]);
alpar@1
   960
//
alpar@1
   961
// DESCRIPTION
alpar@1
   962
//
alpar@1
   963
// The routine lux_solve solves either the system A*x = b (if the flag
alpar@1
   964
// tr is zero) or the system A'*x = b (if the flag tr is non-zero),
alpar@1
   965
// where the parameter lux specifies LU-factorization of the matrix A,
alpar@1
   966
// A' is a matrix transposed to A.
alpar@1
   967
//
alpar@1
   968
// On entry the array x should contain elements of the right-hand side
alpar@1
   969
// vector b in locations x[1], ..., x[n], where n is the order of the
alpar@1
   970
// matrix A. On exit this array will contain elements of the solution
alpar@1
   971
// vector x in the same locations. */
alpar@1
   972
alpar@1
   973
void lux_solve(LUX *lux, int tr, mpq_t x[])
alpar@1
   974
{     if (lux->rank < lux->n)
alpar@1
   975
         xfault("lux_solve: LU-factorization has incomplete rank\n");
alpar@1
   976
      if (!tr)
alpar@1
   977
      {  /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
alpar@1
   978
         lux_f_solve(lux, 0, x);
alpar@1
   979
         lux_v_solve(lux, 0, x);
alpar@1
   980
      }
alpar@1
   981
      else
alpar@1
   982
      {  /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
alpar@1
   983
         lux_v_solve(lux, 1, x);
alpar@1
   984
         lux_f_solve(lux, 1, x);
alpar@1
   985
      }
alpar@1
   986
      return;
alpar@1
   987
}
alpar@1
   988
alpar@1
   989
/*----------------------------------------------------------------------
alpar@1
   990
// lux_delete - delete LU-factorization.
alpar@1
   991
//
alpar@1
   992
// SYNOPSIS
alpar@1
   993
//
alpar@1
   994
// #include "glplux.h"
alpar@1
   995
// void lux_delete(LUX *lux);
alpar@1
   996
//
alpar@1
   997
// DESCRIPTION
alpar@1
   998
//
alpar@1
   999
// The routine lux_delete deletes LU-factorization data structure,
alpar@1
  1000
// which the parameter lux points to, freeing all the memory allocated
alpar@1
  1001
// to this object. */
alpar@1
  1002
alpar@1
  1003
void lux_delete(LUX *lux)
alpar@1
  1004
{     int n = lux->n;
alpar@1
  1005
      LUXELM *fij, *vij;
alpar@1
  1006
      int i;
alpar@1
  1007
      for (i = 1; i <= n; i++)
alpar@1
  1008
      {  for (fij = lux->F_row[i]; fij != NULL; fij = fij->r_next)
alpar@1
  1009
            mpq_clear(fij->val);
alpar@1
  1010
         mpq_clear(lux->V_piv[i]);
alpar@1
  1011
         for (vij = lux->V_row[i]; vij != NULL; vij = vij->r_next)
alpar@1
  1012
            mpq_clear(vij->val);
alpar@1
  1013
      }
alpar@1
  1014
      dmp_delete_pool(lux->pool);
alpar@1
  1015
      xfree(lux->F_row);
alpar@1
  1016
      xfree(lux->F_col);
alpar@1
  1017
      xfree(lux->V_piv);
alpar@1
  1018
      xfree(lux->V_row);
alpar@1
  1019
      xfree(lux->V_col);
alpar@1
  1020
      xfree(lux->P_row);
alpar@1
  1021
      xfree(lux->P_col);
alpar@1
  1022
      xfree(lux->Q_row);
alpar@1
  1023
      xfree(lux->Q_col);
alpar@1
  1024
      xfree(lux);
alpar@1
  1025
      return;
alpar@1
  1026
}
alpar@1
  1027
alpar@1
  1028
/* eof */