src/glpfhv.c
changeset 1 c445c931472f
equal deleted inserted replaced
-1:000000000000 0:da67417834ed
       
     1 /* glpfhv.c (LP basis factorization, FHV eta file version) */
       
     2 
       
     3 /***********************************************************************
       
     4 *  This code is part of GLPK (GNU Linear Programming Kit).
       
     5 *
       
     6 *  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
       
     7 *  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
       
     8 *  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
       
     9 *  E-mail: <mao@gnu.org>.
       
    10 *
       
    11 *  GLPK is free software: you can redistribute it and/or modify it
       
    12 *  under the terms of the GNU General Public License as published by
       
    13 *  the Free Software Foundation, either version 3 of the License, or
       
    14 *  (at your option) any later version.
       
    15 *
       
    16 *  GLPK is distributed in the hope that it will be useful, but WITHOUT
       
    17 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       
    18 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
       
    19 *  License for more details.
       
    20 *
       
    21 *  You should have received a copy of the GNU General Public License
       
    22 *  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
       
    23 ***********************************************************************/
       
    24 
       
    25 #include "glpfhv.h"
       
    26 #include "glpenv.h"
       
    27 #define xfault xerror
       
    28 
       
    29 /* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
       
    30 
       
    31 #define M_MAX 100000000 /* = 100*10^6 */
       
    32 /* maximal order of the basis matrix */
       
    33 
       
    34 /***********************************************************************
       
    35 *  NAME
       
    36 *
       
    37 *  fhv_create_it - create LP basis factorization
       
    38 *
       
    39 *  SYNOPSIS
       
    40 *
       
    41 *  #include "glpfhv.h"
       
    42 *  FHV *fhv_create_it(void);
       
    43 *
       
    44 *  DESCRIPTION
       
    45 *
       
    46 *  The routine fhv_create_it creates a program object, which represents
       
    47 *  a factorization of LP basis.
       
    48 *
       
    49 *  RETURNS
       
    50 *
       
    51 *  The routine fhv_create_it returns a pointer to the object created. */
       
    52 
       
    53 FHV *fhv_create_it(void)
       
    54 {     FHV *fhv;
       
    55       fhv = xmalloc(sizeof(FHV));
       
    56       fhv->m_max = fhv->m = 0;
       
    57       fhv->valid = 0;
       
    58       fhv->luf = luf_create_it();
       
    59       fhv->hh_max = 50;
       
    60       fhv->hh_nfs = 0;
       
    61       fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
       
    62       fhv->p0_row = fhv->p0_col = NULL;
       
    63       fhv->cc_ind = NULL;
       
    64       fhv->cc_val = NULL;
       
    65       fhv->upd_tol = 1e-6;
       
    66       fhv->nnz_h = 0;
       
    67       return fhv;
       
    68 }
       
    69 
       
    70 /***********************************************************************
       
    71 *  NAME
       
    72 *
       
    73 *  fhv_factorize - compute LP basis factorization
       
    74 *
       
    75 *  SYNOPSIS
       
    76 *
       
    77 *  #include "glpfhv.h"
       
    78 *  int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
       
    79 *     int ind[], double val[]), void *info);
       
    80 *
       
    81 *  DESCRIPTION
       
    82 *
       
    83 *  The routine fhv_factorize computes the factorization of the basis
       
    84 *  matrix B specified by the routine col.
       
    85 *
       
    86 *  The parameter fhv specified the basis factorization data structure
       
    87 *  created by the routine fhv_create_it.
       
    88 *
       
    89 *  The parameter m specifies the order of B, m > 0.
       
    90 *
       
    91 *  The formal routine col specifies the matrix B to be factorized. To
       
    92 *  obtain j-th column of A the routine fhv_factorize calls the routine
       
    93 *  col with the parameter j (1 <= j <= n). In response the routine col
       
    94 *  should store row indices and numerical values of non-zero elements
       
    95 *  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
       
    96 *  respectively, where len is the number of non-zeros in j-th column
       
    97 *  returned on exit. Neither zero nor duplicate elements are allowed.
       
    98 *
       
    99 *  The parameter info is a transit pointer passed to the routine col.
       
   100 *
       
   101 *  RETURNS
       
   102 *
       
   103 *  0  The factorization has been successfully computed.
       
   104 *
       
   105 *  FHV_ESING
       
   106 *     The specified matrix is singular within the working precision.
       
   107 *
       
   108 *  FHV_ECOND
       
   109 *     The specified matrix is ill-conditioned.
       
   110 *
       
   111 *  For more details see comments to the routine luf_factorize.
       
   112 *
       
   113 *  ALGORITHM
       
   114 *
       
   115 *  The routine fhv_factorize calls the routine luf_factorize (see the
       
   116 *  module GLPLUF), which actually computes LU-factorization of the basis
       
   117 *  matrix B in the form
       
   118 *
       
   119 *     [B] = (F, V, P, Q),
       
   120 *
       
   121 *  where F and V are such matrices that
       
   122 *
       
   123 *     B = F * V,
       
   124 *
       
   125 *  and P and Q are such permutation matrices that the matrix
       
   126 *
       
   127 *     L = P * F * inv(P)
       
   128 *
       
   129 *  is lower triangular with unity diagonal, and the matrix
       
   130 *
       
   131 *     U = P * V * Q
       
   132 *
       
   133 *  is upper triangular.
       
   134 *
       
   135 *  In order to build the complete representation of the factorization
       
   136 *  (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
       
   137 *  additionally sets H = I and P0 = P. */
       
   138 
       
   139 int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
       
   140       int ind[], double val[]), void *info)
       
   141 {     int ret;
       
   142       if (m < 1)
       
   143          xfault("fhv_factorize: m = %d; invalid parameter\n", m);
       
   144       if (m > M_MAX)
       
   145          xfault("fhv_factorize: m = %d; matrix too big\n", m);
       
   146       fhv->m = m;
       
   147       /* invalidate the factorization */
       
   148       fhv->valid = 0;
       
   149       /* allocate/reallocate arrays, if necessary */
       
   150       if (fhv->hh_ind == NULL)
       
   151          fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
       
   152       if (fhv->hh_ptr == NULL)
       
   153          fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
       
   154       if (fhv->hh_len == NULL)
       
   155          fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
       
   156       if (fhv->m_max < m)
       
   157       {  if (fhv->p0_row != NULL) xfree(fhv->p0_row);
       
   158          if (fhv->p0_col != NULL) xfree(fhv->p0_col);
       
   159          if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
       
   160          if (fhv->cc_val != NULL) xfree(fhv->cc_val);
       
   161          fhv->m_max = m + 100;
       
   162          fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
       
   163          fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
       
   164          fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
       
   165          fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
       
   166       }
       
   167       /* try to factorize the basis matrix */
       
   168       switch (luf_factorize(fhv->luf, m, col, info))
       
   169       {  case 0:
       
   170             break;
       
   171          case LUF_ESING:
       
   172             ret = FHV_ESING;
       
   173             goto done;
       
   174          case LUF_ECOND:
       
   175             ret = FHV_ECOND;
       
   176             goto done;
       
   177          default:
       
   178             xassert(fhv != fhv);
       
   179       }
       
   180       /* the basis matrix has been successfully factorized */
       
   181       fhv->valid = 1;
       
   182       /* H := I */
       
   183       fhv->hh_nfs = 0;
       
   184       /* P0 := P */
       
   185       memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
       
   186       memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
       
   187       /* currently H has no factors */
       
   188       fhv->nnz_h = 0;
       
   189       ret = 0;
       
   190 done: /* return to the calling program */
       
   191       return ret;
       
   192 }
       
   193 
       
   194 /***********************************************************************
       
   195 *  NAME
       
   196 *
       
   197 *  fhv_h_solve - solve system H*x = b or H'*x = b
       
   198 *
       
   199 *  SYNOPSIS
       
   200 *
       
   201 *  #include "glpfhv.h"
       
   202 *  void fhv_h_solve(FHV *fhv, int tr, double x[]);
       
   203 *
       
   204 *  DESCRIPTION
       
   205 *
       
   206 *  The routine fhv_h_solve solves either the system H*x = b (if the
       
   207 *  flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
       
   208 *  where the matrix H is a component of the factorization specified by
       
   209 *  the parameter fhv, H' is a matrix transposed to H.
       
   210 *
       
   211 *  On entry the array x should contain elements of the right-hand side
       
   212 *  vector b in locations x[1], ..., x[m], where m is the order of the
       
   213 *  matrix H. On exit this array will contain elements of the solution
       
   214 *  vector x in the same locations. */
       
   215 
       
   216 void fhv_h_solve(FHV *fhv, int tr, double x[])
       
   217 {     int nfs = fhv->hh_nfs;
       
   218       int *hh_ind = fhv->hh_ind;
       
   219       int *hh_ptr = fhv->hh_ptr;
       
   220       int *hh_len = fhv->hh_len;
       
   221       int *sv_ind = fhv->luf->sv_ind;
       
   222       double *sv_val = fhv->luf->sv_val;
       
   223       int i, k, beg, end, ptr;
       
   224       double temp;
       
   225       if (!fhv->valid)
       
   226          xfault("fhv_h_solve: the factorization is not valid\n");
       
   227       if (!tr)
       
   228       {  /* solve the system H*x = b */
       
   229          for (k = 1; k <= nfs; k++)
       
   230          {  i = hh_ind[k];
       
   231             temp = x[i];
       
   232             beg = hh_ptr[k];
       
   233             end = beg + hh_len[k] - 1;
       
   234             for (ptr = beg; ptr <= end; ptr++)
       
   235                temp -= sv_val[ptr] * x[sv_ind[ptr]];
       
   236             x[i] = temp;
       
   237          }
       
   238       }
       
   239       else
       
   240       {  /* solve the system H'*x = b */
       
   241          for (k = nfs; k >= 1; k--)
       
   242          {  i = hh_ind[k];
       
   243             temp = x[i];
       
   244             if (temp == 0.0) continue;
       
   245             beg = hh_ptr[k];
       
   246             end = beg + hh_len[k] - 1;
       
   247             for (ptr = beg; ptr <= end; ptr++)
       
   248                x[sv_ind[ptr]] -= sv_val[ptr] * temp;
       
   249          }
       
   250       }
       
   251       return;
       
   252 }
       
   253 
       
   254 /***********************************************************************
       
   255 *  NAME
       
   256 *
       
   257 *  fhv_ftran - perform forward transformation (solve system B*x = b)
       
   258 *
       
   259 *  SYNOPSIS
       
   260 *
       
   261 *  #include "glpfhv.h"
       
   262 *  void fhv_ftran(FHV *fhv, double x[]);
       
   263 *
       
   264 *  DESCRIPTION
       
   265 *
       
   266 *  The routine fhv_ftran performs forward transformation, i.e. solves
       
   267 *  the system B*x = b, where B is the basis matrix, x is the vector of
       
   268 *  unknowns to be computed, b is the vector of right-hand sides.
       
   269 *
       
   270 *  On entry elements of the vector b should be stored in dense format
       
   271 *  in locations x[1], ..., x[m], where m is the number of rows. On exit
       
   272 *  the routine stores elements of the vector x in the same locations. */
       
   273 
       
   274 void fhv_ftran(FHV *fhv, double x[])
       
   275 {     int *pp_row = fhv->luf->pp_row;
       
   276       int *pp_col = fhv->luf->pp_col;
       
   277       int *p0_row = fhv->p0_row;
       
   278       int *p0_col = fhv->p0_col;
       
   279       if (!fhv->valid)
       
   280          xfault("fhv_ftran: the factorization is not valid\n");
       
   281       /* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
       
   282       fhv->luf->pp_row = p0_row;
       
   283       fhv->luf->pp_col = p0_col;
       
   284       luf_f_solve(fhv->luf, 0, x);
       
   285       fhv->luf->pp_row = pp_row;
       
   286       fhv->luf->pp_col = pp_col;
       
   287       fhv_h_solve(fhv, 0, x);
       
   288       luf_v_solve(fhv->luf, 0, x);
       
   289       return;
       
   290 }
       
   291 
       
   292 /***********************************************************************
       
   293 *  NAME
       
   294 *
       
   295 *  fhv_btran - perform backward transformation (solve system B'*x = b)
       
   296 *
       
   297 *  SYNOPSIS
       
   298 *
       
   299 *  #include "glpfhv.h"
       
   300 *  void fhv_btran(FHV *fhv, double x[]);
       
   301 *
       
   302 *  DESCRIPTION
       
   303 *
       
   304 *  The routine fhv_btran performs backward transformation, i.e. solves
       
   305 *  the system B'*x = b, where B' is a matrix transposed to the basis
       
   306 *  matrix B, x is the vector of unknowns to be computed, b is the vector
       
   307 *  of right-hand sides.
       
   308 *
       
   309 *  On entry elements of the vector b should be stored in dense format
       
   310 *  in locations x[1], ..., x[m], where m is the number of rows. On exit
       
   311 *  the routine stores elements of the vector x in the same locations. */
       
   312 
       
   313 void fhv_btran(FHV *fhv, double x[])
       
   314 {     int *pp_row = fhv->luf->pp_row;
       
   315       int *pp_col = fhv->luf->pp_col;
       
   316       int *p0_row = fhv->p0_row;
       
   317       int *p0_col = fhv->p0_col;
       
   318       if (!fhv->valid)
       
   319          xfault("fhv_btran: the factorization is not valid\n");
       
   320       /* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
       
   321       luf_v_solve(fhv->luf, 1, x);
       
   322       fhv_h_solve(fhv, 1, x);
       
   323       fhv->luf->pp_row = p0_row;
       
   324       fhv->luf->pp_col = p0_col;
       
   325       luf_f_solve(fhv->luf, 1, x);
       
   326       fhv->luf->pp_row = pp_row;
       
   327       fhv->luf->pp_col = pp_col;
       
   328       return;
       
   329 }
       
   330 
       
   331 /***********************************************************************
       
   332 *  NAME
       
   333 *
       
   334 *  fhv_update_it - update LP basis factorization
       
   335 *
       
   336 *  SYNOPSIS
       
   337 *
       
   338 *  #include "glpfhv.h"
       
   339 *  int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
       
   340 *     const double val[]);
       
   341 *
       
   342 *  DESCRIPTION
       
   343 *
       
   344 *  The routine fhv_update_it updates the factorization of the basis
       
   345 *  matrix B after replacing its j-th column by a new vector.
       
   346 *
       
   347 *  The parameter j specifies the number of column of B, which has been
       
   348 *  replaced, 1 <= j <= m, where m is the order of B.
       
   349 *
       
   350 *  Row indices and numerical values of non-zero elements of the new
       
   351 *  column of B should be placed in locations ind[1], ..., ind[len] and
       
   352 *  val[1], ..., val[len], resp., where len is the number of non-zeros
       
   353 *  in the column. Neither zero nor duplicate elements are allowed.
       
   354 *
       
   355 *  RETURNS
       
   356 *
       
   357 *  0  The factorization has been successfully updated.
       
   358 *
       
   359 *  FHV_ESING
       
   360 *     The adjacent basis matrix is structurally singular, since after
       
   361 *     changing j-th column of matrix V by the new column (see algorithm
       
   362 *     below) the case k1 > k2 occured.
       
   363 *
       
   364 *  FHV_ECHECK
       
   365 *     The factorization is inaccurate, since after transforming k2-th
       
   366 *     row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
       
   367 *     close to zero,
       
   368 *
       
   369 *  FHV_ELIMIT
       
   370 *     Maximal number of H factors has been reached.
       
   371 *
       
   372 *  FHV_EROOM
       
   373 *     Overflow of the sparse vector area.
       
   374 *
       
   375 *  In case of non-zero return code the factorization becomes invalid.
       
   376 *  It should not be used until it has been recomputed with the routine
       
   377 *  fhv_factorize.
       
   378 *
       
   379 *  ALGORITHM
       
   380 *
       
   381 *  The routine fhv_update_it is based on the transformation proposed by
       
   382 *  Forrest and Tomlin.
       
   383 *
       
   384 *  Let j-th column of the basis matrix B have been replaced by new
       
   385 *  column B[j]. In order to keep the equality B = F*H*V j-th column of
       
   386 *  matrix V should be replaced by the column inv(F*H)*B[j].
       
   387 *
       
   388 *  From the standpoint of matrix U = P*V*Q, replacement of j-th column
       
   389 *  of matrix V is equivalent to replacement of k1-th column of matrix U,
       
   390 *  where k1 is determined by permutation matrix Q. Thus, matrix U loses
       
   391 *  its upper triangular form and becomes the following:
       
   392 *
       
   393 *         1   k1       k2   m
       
   394 *     1   x x * x x x x x x x
       
   395 *         . x * x x x x x x x
       
   396 *     k1  . . * x x x x x x x
       
   397 *         . . * x x x x x x x
       
   398 *         . . * . x x x x x x
       
   399 *         . . * . . x x x x x
       
   400 *         . . * . . . x x x x
       
   401 *     k2  . . * . . . . x x x
       
   402 *         . . . . . . . . x x
       
   403 *     m   . . . . . . . . . x
       
   404 *
       
   405 *  where row index k2 corresponds to the lowest non-zero element of
       
   406 *  k1-th column.
       
   407 *
       
   408 *  The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
       
   409 *  by one position to the left and upwards and moves k1-th row and k1-th
       
   410 *  column to position k2. As the result of such symmetric permutations
       
   411 *  matrix U becomes the following:
       
   412 *
       
   413 *         1   k1       k2   m
       
   414 *     1   x x x x x x x * x x
       
   415 *         . x x x x x x * x x
       
   416 *     k1  . . x x x x x * x x
       
   417 *         . . . x x x x * x x
       
   418 *         . . . . x x x * x x
       
   419 *         . . . . . x x * x x
       
   420 *         . . . . . . x * x x
       
   421 *     k2  . . x x x x x * x x
       
   422 *         . . . . . . . . x x
       
   423 *     m   . . . . . . . . . x
       
   424 *
       
   425 *  Then the routine performs gaussian elimination to eliminate elements
       
   426 *  u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
       
   427 *  u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
       
   428 *  as described in comments to the routine luf_factorize (see the module
       
   429 *  GLPLUF). Note that actually all operations are performed on matrix V,
       
   430 *  not on matrix U. During the elimination process the routine permutes
       
   431 *  neither rows nor columns, so only k2-th row of matrix U is changed.
       
   432 *
       
   433 *  To keep the main equality B = F*H*V, each time when the routine
       
   434 *  applies elementary gaussian transformation to the transformed row of
       
   435 *  matrix V (which corresponds to k2-th row of matrix U), it also adds
       
   436 *  a new element (gaussian multiplier) to the current row-like factor
       
   437 *  of matrix H, which corresponds to the transformed row of matrix V. */
       
   438 
       
   439 int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
       
   440       const double val[])
       
   441 {     int m = fhv->m;
       
   442       LUF *luf = fhv->luf;
       
   443       int *vr_ptr = luf->vr_ptr;
       
   444       int *vr_len = luf->vr_len;
       
   445       int *vr_cap = luf->vr_cap;
       
   446       double *vr_piv = luf->vr_piv;
       
   447       int *vc_ptr = luf->vc_ptr;
       
   448       int *vc_len = luf->vc_len;
       
   449       int *vc_cap = luf->vc_cap;
       
   450       int *pp_row = luf->pp_row;
       
   451       int *pp_col = luf->pp_col;
       
   452       int *qq_row = luf->qq_row;
       
   453       int *qq_col = luf->qq_col;
       
   454       int *sv_ind = luf->sv_ind;
       
   455       double *sv_val = luf->sv_val;
       
   456       double *work = luf->work;
       
   457       double eps_tol = luf->eps_tol;
       
   458       int *hh_ind = fhv->hh_ind;
       
   459       int *hh_ptr = fhv->hh_ptr;
       
   460       int *hh_len = fhv->hh_len;
       
   461       int *p0_row = fhv->p0_row;
       
   462       int *p0_col = fhv->p0_col;
       
   463       int *cc_ind = fhv->cc_ind;
       
   464       double *cc_val = fhv->cc_val;
       
   465       double upd_tol = fhv->upd_tol;
       
   466       int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
       
   467          p_beg, p_end, p_ptr, ptr, ret;
       
   468       double f, temp;
       
   469       if (!fhv->valid)
       
   470          xfault("fhv_update_it: the factorization is not valid\n");
       
   471       if (!(1 <= j && j <= m))
       
   472          xfault("fhv_update_it: j = %d; column number out of range\n",
       
   473             j);
       
   474       /* check if the new factor of matrix H can be created */
       
   475       if (fhv->hh_nfs == fhv->hh_max)
       
   476       {  /* maximal number of updates has been reached */
       
   477          fhv->valid = 0;
       
   478          ret = FHV_ELIMIT;
       
   479          goto done;
       
   480       }
       
   481       /* convert new j-th column of B to dense format */
       
   482       for (i = 1; i <= m; i++)
       
   483          cc_val[i] = 0.0;
       
   484       for (k = 1; k <= len; k++)
       
   485       {  i = ind[k];
       
   486          if (!(1 <= i && i <= m))
       
   487             xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
       
   488                "e\n", k, i);
       
   489          if (cc_val[i] != 0.0)
       
   490             xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
       
   491                "t allowed\n", k, i);
       
   492          if (val[k] == 0.0)
       
   493             xfault("fhv_update_it: val[%d] = %g; zero element not allow"
       
   494                "ed\n", k, val[k]);
       
   495          cc_val[i] = val[k];
       
   496       }
       
   497       /* new j-th column of V := inv(F * H) * (new B[j]) */
       
   498       fhv->luf->pp_row = p0_row;
       
   499       fhv->luf->pp_col = p0_col;
       
   500       luf_f_solve(fhv->luf, 0, cc_val);
       
   501       fhv->luf->pp_row = pp_row;
       
   502       fhv->luf->pp_col = pp_col;
       
   503       fhv_h_solve(fhv, 0, cc_val);
       
   504       /* convert new j-th column of V to sparse format */
       
   505       len = 0;
       
   506       for (i = 1; i <= m; i++)
       
   507       {  temp = cc_val[i];
       
   508          if (temp == 0.0 || fabs(temp) < eps_tol) continue;
       
   509          len++, cc_ind[len] = i, cc_val[len] = temp;
       
   510       }
       
   511       /* clear old content of j-th column of matrix V */
       
   512       j_beg = vc_ptr[j];
       
   513       j_end = j_beg + vc_len[j] - 1;
       
   514       for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
       
   515       {  /* get row index of v[i,j] */
       
   516          i = sv_ind[j_ptr];
       
   517          /* find v[i,j] in the i-th row */
       
   518          i_beg = vr_ptr[i];
       
   519          i_end = i_beg + vr_len[i] - 1;
       
   520          for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
       
   521          xassert(i_ptr <= i_end);
       
   522          /* remove v[i,j] from the i-th row */
       
   523          sv_ind[i_ptr] = sv_ind[i_end];
       
   524          sv_val[i_ptr] = sv_val[i_end];
       
   525          vr_len[i]--;
       
   526       }
       
   527       /* now j-th column of matrix V is empty */
       
   528       luf->nnz_v -= vc_len[j];
       
   529       vc_len[j] = 0;
       
   530       /* add new elements of j-th column of matrix V to corresponding
       
   531          row lists; determine indices k1 and k2 */
       
   532       k1 = qq_row[j], k2 = 0;
       
   533       for (ptr = 1; ptr <= len; ptr++)
       
   534       {  /* get row index of v[i,j] */
       
   535          i = cc_ind[ptr];
       
   536          /* at least one unused location is needed in i-th row */
       
   537          if (vr_len[i] + 1 > vr_cap[i])
       
   538          {  if (luf_enlarge_row(luf, i, vr_len[i] + 10))
       
   539             {  /* overflow of the sparse vector area */
       
   540                fhv->valid = 0;
       
   541                luf->new_sva = luf->sv_size + luf->sv_size;
       
   542                xassert(luf->new_sva > luf->sv_size);
       
   543                ret = FHV_EROOM;
       
   544                goto done;
       
   545             }
       
   546          }
       
   547          /* add v[i,j] to i-th row */
       
   548          i_ptr = vr_ptr[i] + vr_len[i];
       
   549          sv_ind[i_ptr] = j;
       
   550          sv_val[i_ptr] = cc_val[ptr];
       
   551          vr_len[i]++;
       
   552          /* adjust index k2 */
       
   553          if (k2 < pp_col[i]) k2 = pp_col[i];
       
   554       }
       
   555       /* capacity of j-th column (which is currently empty) should be
       
   556          not less than len locations */
       
   557       if (vc_cap[j] < len)
       
   558       {  if (luf_enlarge_col(luf, j, len))
       
   559          {  /* overflow of the sparse vector area */
       
   560             fhv->valid = 0;
       
   561             luf->new_sva = luf->sv_size + luf->sv_size;
       
   562             xassert(luf->new_sva > luf->sv_size);
       
   563             ret = FHV_EROOM;
       
   564             goto done;
       
   565          }
       
   566       }
       
   567       /* add new elements of matrix V to j-th column list */
       
   568       j_ptr = vc_ptr[j];
       
   569       memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
       
   570       memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
       
   571       vc_len[j] = len;
       
   572       luf->nnz_v += len;
       
   573       /* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
       
   574          therefore the adjacent basis matrix is structurally singular */
       
   575       if (k1 > k2)
       
   576       {  fhv->valid = 0;
       
   577          ret = FHV_ESING;
       
   578          goto done;
       
   579       }
       
   580       /* perform implicit symmetric permutations of rows and columns of
       
   581          matrix U */
       
   582       i = pp_row[k1], j = qq_col[k1];
       
   583       for (k = k1; k < k2; k++)
       
   584       {  pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
       
   585          qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
       
   586       }
       
   587       pp_row[k2] = i, pp_col[i] = k2;
       
   588       qq_col[k2] = j, qq_row[j] = k2;
       
   589       /* now i-th row of the matrix V is k2-th row of matrix U; since
       
   590          no pivoting is used, only this row will be transformed */
       
   591       /* copy elements of i-th row of matrix V to the working array and
       
   592          remove these elements from matrix V */
       
   593       for (j = 1; j <= m; j++) work[j] = 0.0;
       
   594       i_beg = vr_ptr[i];
       
   595       i_end = i_beg + vr_len[i] - 1;
       
   596       for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
       
   597       {  /* get column index of v[i,j] */
       
   598          j = sv_ind[i_ptr];
       
   599          /* store v[i,j] to the working array */
       
   600          work[j] = sv_val[i_ptr];
       
   601          /* find v[i,j] in the j-th column */
       
   602          j_beg = vc_ptr[j];
       
   603          j_end = j_beg + vc_len[j] - 1;
       
   604          for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
       
   605          xassert(j_ptr <= j_end);
       
   606          /* remove v[i,j] from the j-th column */
       
   607          sv_ind[j_ptr] = sv_ind[j_end];
       
   608          sv_val[j_ptr] = sv_val[j_end];
       
   609          vc_len[j]--;
       
   610       }
       
   611       /* now i-th row of matrix V is empty */
       
   612       luf->nnz_v -= vr_len[i];
       
   613       vr_len[i] = 0;
       
   614       /* create the next row-like factor of the matrix H; this factor
       
   615          corresponds to i-th (transformed) row */
       
   616       fhv->hh_nfs++;
       
   617       hh_ind[fhv->hh_nfs] = i;
       
   618       /* hh_ptr[] will be set later */
       
   619       hh_len[fhv->hh_nfs] = 0;
       
   620       /* up to (k2 - k1) free locations are needed to add new elements
       
   621          to the non-trivial row of the row-like factor */
       
   622       if (luf->sv_end - luf->sv_beg < k2 - k1)
       
   623       {  luf_defrag_sva(luf);
       
   624          if (luf->sv_end - luf->sv_beg < k2 - k1)
       
   625          {  /* overflow of the sparse vector area */
       
   626             fhv->valid = luf->valid = 0;
       
   627             luf->new_sva = luf->sv_size + luf->sv_size;
       
   628             xassert(luf->new_sva > luf->sv_size);
       
   629             ret = FHV_EROOM;
       
   630             goto done;
       
   631          }
       
   632       }
       
   633       /* eliminate subdiagonal elements of matrix U */
       
   634       for (k = k1; k < k2; k++)
       
   635       {  /* v[p,q] = u[k,k] */
       
   636          p = pp_row[k], q = qq_col[k];
       
   637          /* this is the crucial point, where even tiny non-zeros should
       
   638             not be dropped */
       
   639          if (work[q] == 0.0) continue;
       
   640          /* compute gaussian multiplier f = v[i,q] / v[p,q] */
       
   641          f = work[q] / vr_piv[p];
       
   642          /* perform gaussian transformation:
       
   643             (i-th row) := (i-th row) - f * (p-th row)
       
   644             in order to eliminate v[i,q] = u[k2,k] */
       
   645          p_beg = vr_ptr[p];
       
   646          p_end = p_beg + vr_len[p] - 1;
       
   647          for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
       
   648             work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
       
   649          /* store new element (gaussian multiplier that corresponds to
       
   650             p-th row) in the current row-like factor */
       
   651          luf->sv_end--;
       
   652          sv_ind[luf->sv_end] = p;
       
   653          sv_val[luf->sv_end] = f;
       
   654          hh_len[fhv->hh_nfs]++;
       
   655       }
       
   656       /* set pointer to the current row-like factor of the matrix H
       
   657          (if no elements were added to this factor, it is unity matrix
       
   658          and therefore can be discarded) */
       
   659       if (hh_len[fhv->hh_nfs] == 0)
       
   660          fhv->hh_nfs--;
       
   661       else
       
   662       {  hh_ptr[fhv->hh_nfs] = luf->sv_end;
       
   663          fhv->nnz_h += hh_len[fhv->hh_nfs];
       
   664       }
       
   665       /* store new pivot which corresponds to u[k2,k2] */
       
   666       vr_piv[i] = work[qq_col[k2]];
       
   667       /* new elements of i-th row of matrix V (which are non-diagonal
       
   668          elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
       
   669          contained in the working array; add them to matrix V */
       
   670       len = 0;
       
   671       for (k = k2+1; k <= m; k++)
       
   672       {  /* get column index and value of v[i,j] = u[k2,k] */
       
   673          j = qq_col[k];
       
   674          temp = work[j];
       
   675          /* if v[i,j] is close to zero, skip it */
       
   676          if (fabs(temp) < eps_tol) continue;
       
   677          /* at least one unused location is needed in j-th column */
       
   678          if (vc_len[j] + 1 > vc_cap[j])
       
   679          {  if (luf_enlarge_col(luf, j, vc_len[j] + 10))
       
   680             {  /* overflow of the sparse vector area */
       
   681                fhv->valid = 0;
       
   682                luf->new_sva = luf->sv_size + luf->sv_size;
       
   683                xassert(luf->new_sva > luf->sv_size);
       
   684                ret = FHV_EROOM;
       
   685                goto done;
       
   686             }
       
   687          }
       
   688          /* add v[i,j] to j-th column */
       
   689          j_ptr = vc_ptr[j] + vc_len[j];
       
   690          sv_ind[j_ptr] = i;
       
   691          sv_val[j_ptr] = temp;
       
   692          vc_len[j]++;
       
   693          /* also store v[i,j] to the auxiliary array */
       
   694          len++, cc_ind[len] = j, cc_val[len] = temp;
       
   695       }
       
   696       /* capacity of i-th row (which is currently empty) should be not
       
   697          less than len locations */
       
   698       if (vr_cap[i] < len)
       
   699       {  if (luf_enlarge_row(luf, i, len))
       
   700          {  /* overflow of the sparse vector area */
       
   701             fhv->valid = 0;
       
   702             luf->new_sva = luf->sv_size + luf->sv_size;
       
   703             xassert(luf->new_sva > luf->sv_size);
       
   704             ret = FHV_EROOM;
       
   705             goto done;
       
   706          }
       
   707       }
       
   708       /* add new elements to i-th row list */
       
   709       i_ptr = vr_ptr[i];
       
   710       memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
       
   711       memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
       
   712       vr_len[i] = len;
       
   713       luf->nnz_v += len;
       
   714       /* updating is finished; check that diagonal element u[k2,k2] is
       
   715          not very small in absolute value among other elements in k2-th
       
   716          row and k2-th column of matrix U = P*V*Q */
       
   717       /* temp = max(|u[k2,*]|, |u[*,k2]|) */
       
   718       temp = 0.0;
       
   719       /* walk through k2-th row of U which is i-th row of V */
       
   720       i = pp_row[k2];
       
   721       i_beg = vr_ptr[i];
       
   722       i_end = i_beg + vr_len[i] - 1;
       
   723       for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
       
   724          if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
       
   725       /* walk through k2-th column of U which is j-th column of V */
       
   726       j = qq_col[k2];
       
   727       j_beg = vc_ptr[j];
       
   728       j_end = j_beg + vc_len[j] - 1;
       
   729       for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
       
   730          if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
       
   731       /* check that u[k2,k2] is not very small */
       
   732       if (fabs(vr_piv[i]) < upd_tol * temp)
       
   733       {  /* the factorization seems to be inaccurate and therefore must
       
   734             be recomputed */
       
   735          fhv->valid = 0;
       
   736          ret = FHV_ECHECK;
       
   737          goto done;
       
   738       }
       
   739       /* the factorization has been successfully updated */
       
   740       ret = 0;
       
   741 done: /* return to the calling program */
       
   742       return ret;
       
   743 }
       
   744 
       
   745 /***********************************************************************
       
   746 *  NAME
       
   747 *
       
   748 *  fhv_delete_it - delete LP basis factorization
       
   749 *
       
   750 *  SYNOPSIS
       
   751 *
       
   752 *  #include "glpfhv.h"
       
   753 *  void fhv_delete_it(FHV *fhv);
       
   754 *
       
   755 *  DESCRIPTION
       
   756 *
       
   757 *  The routine fhv_delete_it deletes LP basis factorization specified
       
   758 *  by the parameter fhv and frees all memory allocated to this program
       
   759 *  object. */
       
   760 
       
   761 void fhv_delete_it(FHV *fhv)
       
   762 {     luf_delete_it(fhv->luf);
       
   763       if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
       
   764       if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
       
   765       if (fhv->hh_len != NULL) xfree(fhv->hh_len);
       
   766       if (fhv->p0_row != NULL) xfree(fhv->p0_row);
       
   767       if (fhv->p0_col != NULL) xfree(fhv->p0_col);
       
   768       if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
       
   769       if (fhv->cc_val != NULL) xfree(fhv->cc_val);
       
   770       xfree(fhv);
       
   771       return;
       
   772 }
       
   773 
       
   774 /* eof */