src/glpbfd.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
     1 /* glpbfd.c (LP basis factorization driver) */
     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 typedef struct BFD BFD;
    26 
    27 #define GLPBFD_PRIVATE
    28 #include "glpapi.h"
    29 #include "glpfhv.h"
    30 #include "glplpf.h"
    31 
    32 /* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
    33 
    34 #define M_MAX 100000000 /* = 100*10^6 */
    35 /* maximal order of the basis matrix */
    36 
    37 struct BFD
    38 {     /* LP basis factorization */
    39       int valid;
    40       /* factorization is valid only if this flag is set */
    41       int type;
    42       /* factorization type:
    43          GLP_BF_FT - LUF + Forrest-Tomlin
    44          GLP_BF_BG - LUF + Schur compl. + Bartels-Golub
    45          GLP_BF_GR - LUF + Schur compl. + Givens rotation */
    46       FHV *fhv;
    47       /* LP basis factorization (GLP_BF_FT) */
    48       LPF *lpf;
    49       /* LP basis factorization (GLP_BF_BG, GLP_BF_GR) */
    50       int lu_size;      /* luf.sv_size */
    51       double piv_tol;   /* luf.piv_tol */
    52       int piv_lim;      /* luf.piv_lim */
    53       int suhl;         /* luf.suhl */
    54       double eps_tol;   /* luf.eps_tol */
    55       double max_gro;   /* luf.max_gro */
    56       int nfs_max;      /* fhv.hh_max */
    57       double upd_tol;   /* fhv.upd_tol */
    58       int nrs_max;      /* lpf.n_max */
    59       int rs_size;      /* lpf.v_size */
    60       /* internal control parameters */
    61       int upd_lim;
    62       /* the factorization update limit */
    63       int upd_cnt;
    64       /* the factorization update count */
    65 };
    66 
    67 /***********************************************************************
    68 *  NAME
    69 *
    70 *  bfd_create_it - create LP basis factorization
    71 *
    72 *  SYNOPSIS
    73 *
    74 *  #include "glpbfd.h"
    75 *  BFD *bfd_create_it(void);
    76 *
    77 *  DESCRIPTION
    78 *
    79 *  The routine bfd_create_it creates a program object, which represents
    80 *  a factorization of LP basis.
    81 *
    82 *  RETURNS
    83 *
    84 *  The routine bfd_create_it returns a pointer to the object created. */
    85 
    86 BFD *bfd_create_it(void)
    87 {     BFD *bfd;
    88       bfd = xmalloc(sizeof(BFD));
    89       bfd->valid = 0;
    90       bfd->type = GLP_BF_FT;
    91       bfd->fhv = NULL;
    92       bfd->lpf = NULL;
    93       bfd->lu_size = 0;
    94       bfd->piv_tol = 0.10;
    95       bfd->piv_lim = 4;
    96       bfd->suhl = 1;
    97       bfd->eps_tol = 1e-15;
    98       bfd->max_gro = 1e+10;
    99       bfd->nfs_max = 100;
   100       bfd->upd_tol = 1e-6;
   101       bfd->nrs_max = 100;
   102       bfd->rs_size = 1000;
   103       bfd->upd_lim = -1;
   104       bfd->upd_cnt = 0;
   105       return bfd;
   106 }
   107 
   108 /**********************************************************************/
   109 
   110 void bfd_set_parm(BFD *bfd, const void *_parm)
   111 {     /* change LP basis factorization control parameters */
   112       const glp_bfcp *parm = _parm;
   113       xassert(bfd != NULL);
   114       bfd->type = parm->type;
   115       bfd->lu_size = parm->lu_size;
   116       bfd->piv_tol = parm->piv_tol;
   117       bfd->piv_lim = parm->piv_lim;
   118       bfd->suhl = parm->suhl;
   119       bfd->eps_tol = parm->eps_tol;
   120       bfd->max_gro = parm->max_gro;
   121       bfd->nfs_max = parm->nfs_max;
   122       bfd->upd_tol = parm->upd_tol;
   123       bfd->nrs_max = parm->nrs_max;
   124       bfd->rs_size = parm->rs_size;
   125       return;
   126 }
   127 
   128 /***********************************************************************
   129 *  NAME
   130 *
   131 *  bfd_factorize - compute LP basis factorization
   132 *
   133 *  SYNOPSIS
   134 *
   135 *  #include "glpbfd.h"
   136 *  int bfd_factorize(BFD *bfd, int m, int bh[], int (*col)(void *info,
   137 *     int j, int ind[], double val[]), void *info);
   138 *
   139 *  DESCRIPTION
   140 *
   141 *  The routine bfd_factorize computes the factorization of the basis
   142 *  matrix B specified by the routine col.
   143 *
   144 *  The parameter bfd specified the basis factorization data structure
   145 *  created with the routine bfd_create_it.
   146 *
   147 *  The parameter m specifies the order of B, m > 0.
   148 *
   149 *  The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
   150 *  number of j-th column of B in some original matrix. The array bh is
   151 *  optional and can be specified as NULL.
   152 *
   153 *  The formal routine col specifies the matrix B to be factorized. To
   154 *  obtain j-th column of A the routine bfd_factorize calls the routine
   155 *  col with the parameter j (1 <= j <= n). In response the routine col
   156 *  should store row indices and numerical values of non-zero elements
   157 *  of j-th column of B to locations ind[1,...,len] and val[1,...,len],
   158 *  respectively, where len is the number of non-zeros in j-th column
   159 *  returned on exit. Neither zero nor duplicate elements are allowed.
   160 *
   161 *  The parameter info is a transit pointer passed to the routine col.
   162 *
   163 *  RETURNS
   164 *
   165 *  0  The factorization has been successfully computed.
   166 *
   167 *  BFD_ESING
   168 *     The specified matrix is singular within the working precision.
   169 *
   170 *  BFD_ECOND
   171 *     The specified matrix is ill-conditioned.
   172 *
   173 *  For more details see comments to the routine luf_factorize. */
   174 
   175 int bfd_factorize(BFD *bfd, int m, const int bh[], int (*col)
   176       (void *info, int j, int ind[], double val[]), void *info)
   177 {     LUF *luf;
   178       int nov, ret;
   179       xassert(bfd != NULL);
   180       xassert(1 <= m && m <= M_MAX);
   181       /* invalidate the factorization */
   182       bfd->valid = 0;
   183       /* create the factorization, if necessary */
   184       nov = 0;
   185       switch (bfd->type)
   186       {  case GLP_BF_FT:
   187             if (bfd->lpf != NULL)
   188                lpf_delete_it(bfd->lpf), bfd->lpf = NULL;
   189             if (bfd->fhv == NULL)
   190                bfd->fhv = fhv_create_it(), nov = 1;
   191             break;
   192          case GLP_BF_BG:
   193          case GLP_BF_GR:
   194             if (bfd->fhv != NULL)
   195                fhv_delete_it(bfd->fhv), bfd->fhv = NULL;
   196             if (bfd->lpf == NULL)
   197                bfd->lpf = lpf_create_it(), nov = 1;
   198             break;
   199          default:
   200             xassert(bfd != bfd);
   201       }
   202       /* set control parameters specific to LUF */
   203       if (bfd->fhv != NULL)
   204          luf = bfd->fhv->luf;
   205       else if (bfd->lpf != NULL)
   206          luf = bfd->lpf->luf;
   207       else
   208          xassert(bfd != bfd);
   209       if (nov) luf->new_sva = bfd->lu_size;
   210       luf->piv_tol = bfd->piv_tol;
   211       luf->piv_lim = bfd->piv_lim;
   212       luf->suhl = bfd->suhl;
   213       luf->eps_tol = bfd->eps_tol;
   214       luf->max_gro = bfd->max_gro;
   215       /* set control parameters specific to FHV */
   216       if (bfd->fhv != NULL)
   217       {  if (nov) bfd->fhv->hh_max = bfd->nfs_max;
   218          bfd->fhv->upd_tol = bfd->upd_tol;
   219       }
   220       /* set control parameters specific to LPF */
   221       if (bfd->lpf != NULL)
   222       {  if (nov) bfd->lpf->n_max = bfd->nrs_max;
   223          if (nov) bfd->lpf->v_size = bfd->rs_size;
   224       }
   225       /* try to factorize the basis matrix */
   226       if (bfd->fhv != NULL)
   227       {  switch (fhv_factorize(bfd->fhv, m, col, info))
   228          {  case 0:
   229                break;
   230             case FHV_ESING:
   231                ret = BFD_ESING;
   232                goto done;
   233             case FHV_ECOND:
   234                ret = BFD_ECOND;
   235                goto done;
   236             default:
   237                xassert(bfd != bfd);
   238          }
   239       }
   240       else if (bfd->lpf != NULL)
   241       {  switch (lpf_factorize(bfd->lpf, m, bh, col, info))
   242          {  case 0:
   243                /* set the Schur complement update type */
   244                switch (bfd->type)
   245                {  case GLP_BF_BG:
   246                      /* Bartels-Golub update */
   247                      bfd->lpf->scf->t_opt = SCF_TBG;
   248                      break;
   249                   case GLP_BF_GR:
   250                      /* Givens rotation update */
   251                      bfd->lpf->scf->t_opt = SCF_TGR;
   252                      break;
   253                   default:
   254                      xassert(bfd != bfd);
   255                }
   256                break;
   257             case LPF_ESING:
   258                ret = BFD_ESING;
   259                goto done;
   260             case LPF_ECOND:
   261                ret = BFD_ECOND;
   262                goto done;
   263             default:
   264                xassert(bfd != bfd);
   265          }
   266       }
   267       else
   268          xassert(bfd != bfd);
   269       /* the basis matrix has been successfully factorized */
   270       bfd->valid = 1;
   271       bfd->upd_cnt = 0;
   272       ret = 0;
   273 done: /* return to the calling program */
   274       return ret;
   275 }
   276 
   277 /***********************************************************************
   278 *  NAME
   279 *
   280 *  bfd_ftran - perform forward transformation (solve system B*x = b)
   281 *
   282 *  SYNOPSIS
   283 *
   284 *  #include "glpbfd.h"
   285 *  void bfd_ftran(BFD *bfd, double x[]);
   286 *
   287 *  DESCRIPTION
   288 *
   289 *  The routine bfd_ftran performs forward transformation, i.e. solves
   290 *  the system B*x = b, where B is the basis matrix, x is the vector of
   291 *  unknowns to be computed, b is the vector of right-hand sides.
   292 *
   293 *  On entry elements of the vector b should be stored in dense format
   294 *  in locations x[1], ..., x[m], where m is the number of rows. On exit
   295 *  the routine stores elements of the vector x in the same locations. */
   296 
   297 void bfd_ftran(BFD *bfd, double x[])
   298 {     xassert(bfd != NULL);
   299       xassert(bfd->valid);
   300       if (bfd->fhv != NULL)
   301          fhv_ftran(bfd->fhv, x);
   302       else if (bfd->lpf != NULL)
   303          lpf_ftran(bfd->lpf, x);
   304       else
   305          xassert(bfd != bfd);
   306       return;
   307 }
   308 
   309 /***********************************************************************
   310 *  NAME
   311 *
   312 *  bfd_btran - perform backward transformation (solve system B'*x = b)
   313 *
   314 *  SYNOPSIS
   315 *
   316 *  #include "glpbfd.h"
   317 *  void bfd_btran(BFD *bfd, double x[]);
   318 *
   319 *  DESCRIPTION
   320 *
   321 *  The routine bfd_btran performs backward transformation, i.e. solves
   322 *  the system B'*x = b, where B' is a matrix transposed to the basis
   323 *  matrix B, x is the vector of unknowns to be computed, b is the vector
   324 *  of right-hand sides.
   325 *
   326 *  On entry elements of the vector b should be stored in dense format
   327 *  in locations x[1], ..., x[m], where m is the number of rows. On exit
   328 *  the routine stores elements of the vector x in the same locations. */
   329 
   330 void bfd_btran(BFD *bfd, double x[])
   331 {     xassert(bfd != NULL);
   332       xassert(bfd->valid);
   333       if (bfd->fhv != NULL)
   334          fhv_btran(bfd->fhv, x);
   335       else if (bfd->lpf != NULL)
   336          lpf_btran(bfd->lpf, x);
   337       else
   338          xassert(bfd != bfd);
   339       return;
   340 }
   341 
   342 /***********************************************************************
   343 *  NAME
   344 *
   345 *  bfd_update_it - update LP basis factorization
   346 *
   347 *  SYNOPSIS
   348 *
   349 *  #include "glpbfd.h"
   350 *  int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
   351 *     const double val[]);
   352 *
   353 *  DESCRIPTION
   354 *
   355 *  The routine bfd_update_it updates the factorization of the basis
   356 *  matrix B after replacing its j-th column by a new vector.
   357 *
   358 *  The parameter j specifies the number of column of B, which has been
   359 *  replaced, 1 <= j <= m, where m is the order of B.
   360 *
   361 *  The parameter bh specifies the basis header entry for the new column
   362 *  of B, which is the number of the new column in some original matrix.
   363 *  This parameter is optional and can be specified as 0.
   364 *
   365 *  Row indices and numerical values of non-zero elements of the new
   366 *  column of B should be placed in locations ind[1], ..., ind[len] and
   367 *  val[1], ..., val[len], resp., where len is the number of non-zeros
   368 *  in the column. Neither zero nor duplicate elements are allowed.
   369 *
   370 *  RETURNS
   371 *
   372 *  0  The factorization has been successfully updated.
   373 *
   374 *  BFD_ESING
   375 *     New basis matrix is singular within the working precision.
   376 *
   377 *  BFD_ECHECK
   378 *     The factorization is inaccurate.
   379 *
   380 *  BFD_ELIMIT
   381 *     Factorization update limit has been reached.
   382 *
   383 *  BFD_EROOM
   384 *     Overflow of the sparse vector area.
   385 *
   386 *  In case of non-zero return code the factorization becomes invalid.
   387 *  It should not be used until it has been recomputed with the routine
   388 *  bfd_factorize. */
   389 
   390 int bfd_update_it(BFD *bfd, int j, int bh, int len, const int ind[],
   391       const double val[])
   392 {     int ret;
   393       xassert(bfd != NULL);
   394       xassert(bfd->valid);
   395       /* try to update the factorization */
   396       if (bfd->fhv != NULL)
   397       {  switch (fhv_update_it(bfd->fhv, j, len, ind, val))
   398          {  case 0:
   399                break;
   400             case FHV_ESING:
   401                bfd->valid = 0;
   402                ret = BFD_ESING;
   403                goto done;
   404             case FHV_ECHECK:
   405                bfd->valid = 0;
   406                ret = BFD_ECHECK;
   407                goto done;
   408             case FHV_ELIMIT:
   409                bfd->valid = 0;
   410                ret = BFD_ELIMIT;
   411                goto done;
   412             case FHV_EROOM:
   413                bfd->valid = 0;
   414                ret = BFD_EROOM;
   415                goto done;
   416             default:
   417                xassert(bfd != bfd);
   418          }
   419       }
   420       else if (bfd->lpf != NULL)
   421       {  switch (lpf_update_it(bfd->lpf, j, bh, len, ind, val))
   422          {  case 0:
   423                break;
   424             case LPF_ESING:
   425                bfd->valid = 0;
   426                ret = BFD_ESING;
   427                goto done;
   428             case LPF_ELIMIT:
   429                bfd->valid = 0;
   430                ret = BFD_ELIMIT;
   431                goto done;
   432             default:
   433                xassert(bfd != bfd);
   434          }
   435       }
   436       else
   437          xassert(bfd != bfd);
   438       /* the factorization has been successfully updated */
   439       /* increase the update count */
   440       bfd->upd_cnt++;
   441       ret = 0;
   442 done: /* return to the calling program */
   443       return ret;
   444 }
   445 
   446 /**********************************************************************/
   447 
   448 int bfd_get_count(BFD *bfd)
   449 {     /* determine factorization update count */
   450       xassert(bfd != NULL);
   451       xassert(bfd->valid);
   452       return bfd->upd_cnt;
   453 }
   454 
   455 /***********************************************************************
   456 *  NAME
   457 *
   458 *  bfd_delete_it - delete LP basis factorization
   459 *
   460 *  SYNOPSIS
   461 *
   462 *  #include "glpbfd.h"
   463 *  void bfd_delete_it(BFD *bfd);
   464 *
   465 *  DESCRIPTION
   466 *
   467 *  The routine bfd_delete_it deletes LP basis factorization specified
   468 *  by the parameter fhv and frees all memory allocated to this program
   469 *  object. */
   470 
   471 void bfd_delete_it(BFD *bfd)
   472 {     xassert(bfd != NULL);
   473       if (bfd->fhv != NULL)
   474          fhv_delete_it(bfd->fhv);
   475       if (bfd->lpf != NULL)
   476          lpf_delete_it(bfd->lpf);
   477       xfree(bfd);
   478       return;
   479 }
   480 
   481 /* eof */