dbl_factor.c

Go to the documentation of this file.
00001 /****************************************************************************/
00002 /*                                                                          */
00003 /*  This file is part of QSopt_ex.                                          */
00004 /*                                                                          */
00005 /*  (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash,      */
00006 /*  and Daniel Espinoza                                                     */
00007 /*                                                                          */
00008 /*  Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his     */
00009 /*  copyright in QSopt.                                                     */
00010 /*                                                                          */
00011 /*  This code may be used under the terms of the GNU General Public License */
00012 /*  (Version 2.1 or later) as published by the Free Software Foundation.    */
00013 /*                                                                          */
00014 /*  Alternatively, use is granted for research purposes only.               */
00015 /*                                                                          */
00016 /*  It is your choice of which of these two licenses you are operating      */
00017 /*  under.                                                                  */
00018 /*                                                                          */
00019 /*  We make no guarantees about the correctness or usefulness of this code. */
00020 /*                                                                          */
00021 /****************************************************************************/
00022 
00023 /* RCS_INFO = "$RCSfile: dbl_factor.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */
00024 //static int TRACE = 0;
00025 
00026 /* implement a = max(a,abs(b)) and execute the extra code if the update is
00027  * needed */
00028 #define dbl_EGlpNumSetToMaxAbsAndDo(a,b,c) \
00029   if(dbl_EGlpNumIsGreatZero(b))\
00030   {\
00031     if(dbl_EGlpNumIsLess(a,b)){\
00032       dbl_EGlpNumCopy(a,b);\
00033       c;\
00034       }\
00035   }\
00036   else\
00037   {\
00038     dbl_EGlpNumSign(a);\
00039     if(dbl_EGlpNumIsLess(b,a)){\
00040       dbl_EGlpNumCopy(a,b);\
00041       c;\
00042       }\
00043     dbl_EGlpNumSign(a);\
00044   }
00045 
00046 
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include "config.h"
00050 #include "dbl_iqsutil.h"
00051 #include "dbl_lpdefs.h"
00052 #include "dbl_factor.h"
00053 #ifdef USEDMALLOC
00054 #include "dmalloc.h"
00055 #endif
00056 
00057 
00058 #undef  dbl_RECORD
00059 #undef  dbl_DEBUG_FACTOR
00060 #undef  dbl_SOLVE_DEBUG
00061 
00062 #undef  dbl_FACTOR_DEBUG
00063 #undef  dbl_UPDATE_DEBUG
00064 
00065 #undef dbl_TRACK_FACTOR
00066 #undef dbl_NOTICE_BLOWUP
00067 
00068 #undef  dbl_FACTOR_STATS
00069 #undef  dbl_UPDATE_STATS
00070 #undef  dbl_GROWTH_STATS
00071 
00072 #undef  dbl_UPDATE_STUDY
00073 
00074 #undef  dbl_SORT_RESULTS
00075 
00076 #ifdef dbl_UPDATE_STUDY
00077 int dbl_nupdate = 0;
00078 long int dbl_colspiketot = 0.0;
00079 long int dbl_rowspiketot = 0.0;
00080 long int dbl_permshifttot = 0.0;
00081 long int dbl_leftetatot = 0.0;
00082 #endif
00083 
00084 void dbl_ILLfactor_init_factor_work (
00085   dbl_factor_work * f)
00086 {
00087   f->max_k = 1000;              /* must be less than 46340 (2^15.5) */
00088   dbl_EGlpNumCopy (f->fzero_tol, dbl_SZERO_TOLER);  /* 2^-50 */
00089   dbl_EGlpNumCopy (f->szero_tol, dbl_SZERO_TOLER);  /* 2^-50 */
00090   dbl_EGlpNumCopy (f->partial_tol, dbl_OBJBND_TOLER); /* 2^-7 */
00091   f->ur_space_mul = 2.0;
00092   f->uc_space_mul = 1.1;
00093   f->lc_space_mul = 1.1;
00094   f->er_space_mul = 1000.0;
00095   f->grow_mul = 1.5;
00096   f->p = 4;
00097   f->etamax = 100;
00098   f->minmult = 1e3;
00099   f->maxmult = 1e5;
00100   f->updmaxmult = 1e7;
00101   f->dense_fract = 0.25;
00102   f->dense_min = 25;
00103   dbl_EGlpNumCopy (f->partial_cur, f->partial_tol);
00104   f->work_coef = 0;
00105   f->work_indx = 0;
00106   f->uc_inf = 0;
00107   f->ur_inf = 0;
00108   f->lc_inf = 0;
00109   f->lr_inf = 0;
00110   f->er_inf = 0;
00111   f->ucindx = 0;
00112   f->ucrind = 0;
00113   f->uccoef = 0;
00114   f->urindx = 0;
00115   f->urcind = 0;
00116   f->urcoef = 0;
00117   f->lcindx = 0;
00118   f->lccoef = 0;
00119   f->lrindx = 0;
00120   f->lrcoef = 0;
00121   f->erindx = 0;
00122   f->ercoef = 0;
00123   f->rperm = 0;
00124   f->rrank = 0;
00125   f->cperm = 0;
00126   f->crank = 0;
00127   f->dmat = 0;
00128   dbl_ILLsvector_init (&f->xtmp);
00129 }
00130 
00131 void dbl_ILLfactor_free_factor_work (
00132   dbl_factor_work * f)
00133 {
00134 #ifdef dbl_UPDATE_STUDY
00135   if (dbl_nupdate)
00136   {
00137     MESSAGE(0, "UPDATE STUDY: avg %d upd: %.2f col, %.2f row, %.2f lefteta, "
00138             "%.2f perm", dbl_nupdate, ((double) dbl_colspiketot) / dbl_nupdate, 
00139             ((double) dbl_rowspiketot) / dbl_nupdate, ((double) dbl_leftetatot) / dbl_nupdate,
00140             ((double) dbl_permshifttot) / dbl_nupdate);
00141   }
00142 #endif
00143   dbl_EGlpNumFreeArray (f->work_coef);
00144   ILL_IFFREE (f->work_indx, int);
00145 
00146   ILL_IFFREE (f->uc_inf, dbl_uc_info);
00147   if (f->dim + f->max_k > 0 && f->ur_inf)
00148   {
00149     unsigned int i = f->dim + f->max_k + 1;
00150 
00151     while (i--)
00152       dbl_EGlpNumClearVar (f->ur_inf[i].max);
00153   }
00154   ILL_IFFREE (f->ur_inf, dbl_ur_info);
00155   ILL_IFFREE (f->lc_inf, dbl_lc_info);
00156   ILL_IFFREE (f->lr_inf, dbl_lr_info);
00157   ILL_IFFREE (f->er_inf, dbl_er_info);
00158   ILL_IFFREE (f->ucindx, int);
00159   ILL_IFFREE (f->ucrind, int);
00160 
00161   dbl_EGlpNumFreeArray (f->uccoef);
00162   ILL_IFFREE (f->urindx, int);
00163   ILL_IFFREE (f->urcind, int);
00164 
00165   dbl_EGlpNumFreeArray (f->urcoef);
00166   ILL_IFFREE (f->lcindx, int);
00167 
00168   dbl_EGlpNumFreeArray (f->lccoef);
00169   ILL_IFFREE (f->lrindx, int);
00170 
00171   dbl_EGlpNumFreeArray (f->lrcoef);
00172   ILL_IFFREE (f->erindx, int);
00173 
00174   dbl_EGlpNumFreeArray (f->ercoef);
00175   ILL_IFFREE (f->rperm, int);
00176   ILL_IFFREE (f->rrank, int);
00177   ILL_IFFREE (f->cperm, int);
00178   ILL_IFFREE (f->crank, int);
00179 
00180   dbl_EGlpNumFreeArray (f->dmat);
00181   dbl_ILLsvector_free (&f->xtmp);
00182 }
00183 
00184 int dbl_ILLfactor_set_factor_iparam (
00185   dbl_factor_work * f,
00186   int param,
00187   int val)
00188 {
00189   switch (param)
00190   {
00191   case QS_FACTOR_MAX_K:
00192     f->max_k = val;
00193     break;
00194   case QS_FACTOR_P:
00195     f->p = val;
00196     break;
00197   case QS_FACTOR_ETAMAX:
00198     f->etamax = val;
00199     break;
00200   case QS_FACTOR_DENSE_MIN:
00201     f->dense_min = val;
00202     break;
00203   default:
00204     fprintf (stderr, "Invalid param %d in dbl_ILLfactor_set_factor_iparam\n",
00205              param);
00206     return 1;
00207   }
00208   return 0;
00209 }
00210 
00211 int dbl_ILLfactor_set_factor_dparam (
00212   dbl_factor_work * f,
00213   int param,
00214   double val)
00215 {
00216   switch (param)
00217   {
00218   case QS_FACTOR_FZERO_TOL:
00219     dbl_EGlpNumCopy (f->fzero_tol, val);
00220     break;
00221   case QS_FACTOR_SZERO_TOL:
00222     dbl_EGlpNumCopy (f->szero_tol, val);
00223     break;
00224   case QS_FACTOR_UR_SPACE_MUL:
00225     f->ur_space_mul = dbl_EGlpNumToLf (val);
00226     break;
00227   case QS_FACTOR_UC_SPACE_MUL:
00228     f->uc_space_mul = dbl_EGlpNumToLf (val);
00229     break;
00230   case QS_FACTOR_LC_SPACE_MUL:
00231     f->lc_space_mul = dbl_EGlpNumToLf (val);
00232     break;
00233   case QS_FACTOR_LR_SPACE_MUL:
00234     f->lr_space_mul = dbl_EGlpNumToLf (val);
00235     break;
00236   case QS_FACTOR_ER_SPACE_MUL:
00237     f->er_space_mul = dbl_EGlpNumToLf (val);
00238     break;
00239   case QS_FACTOR_GROW_MUL:
00240     f->grow_mul = dbl_EGlpNumToLf (val);
00241     break;
00242   case QS_FACTOR_MAXMULT:
00243     f->maxmult = dbl_EGlpNumToLf (val);
00244     break;
00245   case QS_FACTOR_UPDMAXMULT:
00246     f->updmaxmult = dbl_EGlpNumToLf (val);
00247     break;
00248   case QS_FACTOR_DENSE_FRACT:
00249     f->dense_fract = dbl_EGlpNumToLf (val);
00250     break;
00251   case QS_FACTOR_PARTIAL_TOL:
00252     dbl_EGlpNumCopy (f->partial_tol, val);
00253     dbl_EGlpNumCopy (f->partial_cur, val);
00254     break;
00255   default:
00256     fprintf (stderr, "Invalid param %d in dbl_ILLfactor_set_factor_dparam\n",
00257              param);
00258     return 1;
00259   }
00260   return 0;
00261 }
00262 
00263 int dbl_ILLfactor_create_factor_work (
00264   dbl_factor_work * f,
00265   int dim)
00266 {
00267   int i;
00268   int rval;
00269 
00270   f->dim = dim;
00271   f->etacnt = 0;
00272   f->work_coef = dbl_EGlpNumAllocArray (dim);
00273   ILL_SAFE_MALLOC (f->work_indx, dim, int);
00274 
00275   ILL_SAFE_MALLOC (f->uc_inf, dim + (f->max_k + 1), dbl_uc_info);
00276   ILL_SAFE_MALLOC (f->ur_inf, dim + (f->max_k + 1), dbl_ur_info);
00277   ILL_SAFE_MALLOC (f->lc_inf, dim, dbl_lc_info);
00278   ILL_SAFE_MALLOC (f->lr_inf, dim, dbl_lr_info);
00279   ILL_SAFE_MALLOC (f->rperm, dim, int);
00280   ILL_SAFE_MALLOC (f->rrank, dim, int);
00281   ILL_SAFE_MALLOC (f->cperm, dim, int);
00282   ILL_SAFE_MALLOC (f->crank, dim, int);
00283 
00284   for (i = dim + f->max_k + 1; i--;)
00285     dbl_EGlpNumInitVar (f->ur_inf[i].max);
00286 
00287   for (i = 0; i < dim; i++)
00288   {
00289     dbl_EGlpNumZero (f->work_coef[i]);
00290     f->work_indx[i] = 0;
00291     f->uc_inf[i].nzcnt = 0;
00292     f->ur_inf[i].nzcnt = 0;
00293     f->lc_inf[i].nzcnt = 0;
00294     f->lr_inf[i].nzcnt = 0;
00295     f->rperm[i] = i;
00296     f->rrank[i] = i;
00297     f->cperm[i] = i;
00298     f->crank[i] = i;
00299   }
00300   for (i = 0; i <= f->max_k; i++)
00301   {
00302     f->uc_inf[dim + i].nzcnt = i;
00303     f->uc_inf[dim + i].next = dim + i;
00304     f->uc_inf[dim + i].prev = dim + i;
00305     f->ur_inf[dim + i].nzcnt = i;
00306     f->ur_inf[dim + i].next = dim + i;
00307     f->ur_inf[dim + i].prev = dim + i;
00308   }
00309 
00310   rval = dbl_ILLsvector_alloc (&f->xtmp, dim);
00311   CHECKRVALG (rval, CLEANUP);
00312 
00313   rval = 0;
00314 
00315 CLEANUP:
00316   if (rval)
00317   {
00318     dbl_ILLfactor_free_factor_work (f);
00319   }
00320   EG_RETURN (rval);
00321 }
00322 
00323 static void dbl_dump_matrix (
00324   dbl_factor_work * f,
00325   int remaining)
00326 {
00327   int dim = f->dim;
00328   dbl_ur_info *ur_inf = f->ur_inf;
00329   dbl_uc_info *uc_inf = f->uc_inf;
00330   dbl_lc_info *lc_inf = f->lc_inf;
00331   dbl_lr_info *lr_inf = f->lr_inf;
00332   dbl_er_info *er_inf = f->er_inf;
00333   int nzcnt;
00334   int beg;
00335 
00336   int i;
00337   int j;
00338 
00339   for (i = 0; i < dim; i++)
00340   {
00341     if (!remaining || ur_inf[i].next >= 0)
00342     {
00343       printf ("Row %d %d (max %.3f):", i, f->rrank[i],
00344               dbl_EGlpNumToLf (ur_inf[i].max));
00345       nzcnt = ur_inf[i].nzcnt;
00346       beg = ur_inf[i].rbeg;
00347       for (j = 0; j < nzcnt; j++)
00348       {
00349         if (j == ur_inf[i].pivcnt)
00350         {
00351           printf (" |");
00352         }
00353         printf (" %.3f*%d", dbl_EGlpNumToLf (f->urcoef[beg + j]),
00354                 f->urindx[beg + j]);
00355         if (f->urcind)
00356           printf ("@%d", f->urcind[beg + j]);
00357       }
00358       printf ("\n");
00359     }
00360   }
00361   if (f->dmat)
00362   {
00363     int start = 0;
00364 
00365     if (remaining)
00366       start = f->stage - f->dense_base;
00367     printf ("Dcols at %d %d - %d    :", f->stage - f->dense_base,
00368             f->dense_base + start, f->nstages);
00369     for (j = start; j < f->dcols; j++)
00370     {
00371       printf (" %5d", f->cperm[j + f->dense_base]);
00372     }
00373     printf ("\n");
00374     for (i = start; i < f->drows; i++)
00375     {
00376       printf ("DRow %d %d (max %.3f):", i,
00377               f->rperm[i + f->dense_base],
00378               dbl_EGlpNumToLf (ur_inf[f->rperm[i + f->dense_base]].max));
00379       for (j = start; j < f->dcols; j++)
00380       {
00381         if (j == f->drows)
00382         {
00383           printf (" |");
00384         }
00385         printf (" %.3f", dbl_EGlpNumToLf (f->dmat[i * f->dcols + j]));
00386       }
00387       printf ("\n");
00388     }
00389   }
00390 
00391   if (!remaining)
00392   {
00393     for (i = 0; i < f->stage; i++)
00394     {
00395       printf ("L col %d:", lc_inf[i].c);
00396       nzcnt = lc_inf[i].nzcnt;
00397       beg = lc_inf[i].cbeg;
00398       for (j = 0; j < nzcnt; j++)
00399       {
00400         printf (" %.3f*%d", dbl_EGlpNumToLf (f->lccoef[beg + j]),
00401                 f->lcindx[beg + j]);
00402       }
00403       printf ("\n");
00404     }
00405     for (i = f->nstages; i < f->dim; i++)
00406     {
00407       printf ("L col %d:", lc_inf[i].c);
00408       nzcnt = lc_inf[i].nzcnt;
00409       beg = lc_inf[i].cbeg;
00410       for (j = 0; j < nzcnt; j++)
00411       {
00412         printf (" %.3f*%d", dbl_EGlpNumToLf (f->lccoef[beg + j]),
00413                 f->lcindx[beg + j]);
00414       }
00415       printf ("\n");
00416     }
00417     for (i = 0; i < f->dim; i++)
00418     {
00419       if (!lr_inf[i].nzcnt)
00420         continue;
00421       printf ("L row %d:", lr_inf[i].r);
00422       nzcnt = lr_inf[i].nzcnt;
00423       beg = lr_inf[i].rbeg;
00424       for (j = 0; j < nzcnt; j++)
00425       {
00426         printf (" %.3f*%d", dbl_EGlpNumToLf (f->lrcoef[beg + j]),
00427                 f->lrindx[beg + j]);
00428       }
00429       printf ("\n");
00430     }
00431   }
00432 
00433   if (!remaining)
00434   {
00435     for (i = 0; i < f->etacnt; i++)
00436     {
00437       printf ("Eta row %d:", f->er_inf[i].r);
00438       nzcnt = er_inf[i].nzcnt;
00439       beg = er_inf[i].rbeg;
00440       for (j = 0; j < nzcnt; j++)
00441       {
00442         printf (" %.3f*%d", dbl_EGlpNumToLf (f->ercoef[beg + j]),
00443                 f->erindx[beg + j]);
00444       }
00445       printf ("\n");
00446     }
00447   }
00448 
00449   for (i = 0; i < dim; i++)
00450   {
00451     if (!remaining || uc_inf[i].next >= 0)
00452     {
00453       printf ("Col %d %d:", i, f->crank[i]);
00454       nzcnt = uc_inf[i].nzcnt;
00455       beg = uc_inf[i].cbeg;
00456       for (j = 0; j < nzcnt; j++)
00457       {
00458         if (f->uccoef != 0)
00459         {
00460           printf (" %.3f*%d", dbl_EGlpNumToLf (f->uccoef[beg + j]),
00461                   f->ucindx[beg + j]);
00462           if (f->ucrind)
00463             printf ("@%d", f->ucrind[beg + j]);
00464         }
00465         else
00466         {
00467           printf (" %d", f->ucindx[beg + j]);
00468         }
00469       }
00470       printf ("\n");
00471     }
00472   }
00473 
00474   if (!remaining)
00475   {
00476     printf ("rperm:");
00477     for (i = 0; i < dim; i++)
00478     {
00479       if (i == f->nstages)
00480         printf ("|");
00481       if (i == f->stage)
00482         printf ("|");
00483       printf (" %d", f->rperm[i]);
00484     }
00485     printf ("\n");
00486 
00487     printf ("cperm:");
00488     for (i = 0; i < dim; i++)
00489     {
00490       if (i == f->nstages)
00491         printf ("|");
00492       if (i == f->stage)
00493         printf ("|");
00494       printf (" %d", f->cperm[i]);
00495     }
00496     printf ("\n");
00497   }
00498 
00499   printf ("Rows by nzcnt:\n");
00500   for (i = 0; i <= f->max_k; i++)
00501   {
00502     if (ur_inf[dim + i].next != dim + i)
00503     {
00504       printf ("%d:", i);
00505       for (j = ur_inf[dim + i].next; j != dim + i; j = ur_inf[j].next)
00506       {
00507         printf (" %d", j);
00508       }
00509       printf ("\n");
00510     }
00511   }
00512 
00513   printf ("Cols by nzcnt:\n");
00514   for (i = 0; i <= f->max_k; i++)
00515   {
00516     if (uc_inf[dim + i].next != dim + i)
00517     {
00518       printf ("%d:", i);
00519       for (j = uc_inf[dim + i].next; j != dim + i; j = uc_inf[j].next)
00520       {
00521         printf (" %d", j);
00522       }
00523       printf ("\n");
00524     }
00525   }
00526 
00527   printf ("\n");
00528   fflush (stdout);
00529 }
00530 
00531 #ifdef dbl_SORT_RESULTS
00532 static void dbl_sort_vector2 (
00533   int nzcnt,
00534   int *indx,
00535   double * coef)
00536 {
00537   int i;
00538   int j;
00539   int itmp;
00540   double ctmp;
00541 
00542   dbl_EGlpNumInitVar (ctmp);
00543 
00544   for (i = 1; i < nzcnt; i++)
00545   {
00546     itmp = indx[i];
00547     dbl_EGlpNumCopy (ctmp, coef[i]);
00548     for (j = i; j >= 1 && indx[j - 1] > itmp; j--)
00549     {
00550       indx[j] = indx[j - 1];
00551       dbl_EGlpNumCopy (coef[j], coef[j - 1]);
00552     }
00553     indx[j] = itmp;
00554     dbl_EGlpNumCopy (coef[j], ctmp);
00555   }
00556   dbl_EGlpNumClearVar (ctmp);
00557 }
00558 
00559 static void dbl_sort_vector (
00560   dbl_svector * x)
00561 {
00562   dbl_sort_vector2 (x->nzcnt, x->indx, x->coef);
00563 }
00564 #endif
00565 
00566 #ifdef dbl_DEBUG_FACTOR
00567 static int dbl_check_matrix (
00568   dbl_factor_work * f)
00569 {
00570   dbl_ur_info *ur_inf = f->ur_inf;
00571   dbl_uc_info *uc_inf = f->uc_inf;
00572   int rbeg;
00573   int nzcnt;
00574   int cbeg;
00575   int c;
00576   int r;
00577   int j;
00578   int nerr = 0;
00579 
00580   for (r = 0; r < f->dim; r++)
00581   {
00582     nzcnt = ur_inf[r].nzcnt;
00583     rbeg = ur_inf[r].rbeg;
00584     for (j = 0; j < nzcnt; j++)
00585     {
00586       c = f->urindx[rbeg + j];
00587       cbeg = uc_inf[c].cbeg;
00588       if (f->ucindx[cbeg + f->urcind[rbeg + j]] != r)
00589       {
00590         MESSAGE(0,"index mismatch, row %d column %d", r, c);
00591         nerr++;
00592       }
00593       if (fabs(dbl_EGlpNumToLf(f->uccoef[cbeg + f->urcind[rbeg + j]]) - dbl_EGlpNumToLf(f->urcoef[rbeg + j]))>1000*dbl_EGlpNumToLf(dbl_epsLpNum))
00594       {
00595         MESSAGE(0,"coef mismatch, row %d column %d", r, c);
00596         nerr++;
00597       }
00598     }
00599   }
00600   if (f->urindx[f->ur_space] != 0)
00601   {
00602     MESSAGE(0,"last urindx entry %d != 0", f->urindx[f->ur_space]);
00603     nerr++;
00604   }
00605 
00606   for (c = 0; c < f->dim; c++)
00607   {
00608     nzcnt = uc_inf[c].nzcnt;
00609     cbeg = uc_inf[c].cbeg;
00610     for (j = 0; j < nzcnt; j++)
00611     {
00612       r = f->ucindx[cbeg + j];
00613       rbeg = ur_inf[r].rbeg;
00614       if (f->urindx[rbeg + f->ucrind[cbeg + j]] != c)
00615       {
00616         MESSAGE(0,"index mismatch, column %d row %d", c, r);
00617         nerr++;
00618       }
00619       if (f->urcoef[rbeg + f->ucrind[cbeg + j]] != f->uccoef[cbeg + j])
00620       {
00621         MESSAGE(0,"coef mismatch, column %d row %d", c, r);
00622         nerr++;
00623       }
00624     }
00625   }
00626   if (f->ucindx[f->uc_space] != 0)
00627   {
00628     MESSAGE(0,"last ucindx entry %d != 0", f->ucindx[f->uc_space]);
00629     nerr++;
00630   }
00631   if (nerr)
00632   {
00633     dbl_dump_matrix (f, 0);
00634     return E_CHECK_FAILED;
00635   }
00636   return 0;
00637 }
00638 #endif
00639 
00640 #ifdef dbl_FACTOR_STATS
00641 static void dbl_dump_factor_stats (
00642   dbl_factor_work * f)
00643 {
00644   int dim = f->dim;
00645   int ecnt = f->etacnt;
00646   dbl_ur_info *ur_inf = f->ur_inf;
00647   dbl_lc_info *lc_inf = f->lc_inf;
00648   dbl_er_info *er_inf = f->er_inf;
00649   double *urcoef = f->urcoef;
00650   double *lccoef = f->lccoef;
00651   double *ercoef = f->ercoef;
00652   int lnzcnt = 0;
00653   int unzcnt = 0;
00654   int enzcnt = 0;
00655   int nzcnt;
00656   int beg;
00657   double umax;
00658   double lmax;
00659   double emax;
00660   int i;
00661   int j;
00662 
00663   dbl_EGlpNumInitVar (umax);
00664   dbl_EGlpNumInitVar (lmax);
00665   dbl_EGlpNumInitVar (emax);
00666   dbl_EGlpNumZero (umax);
00667   for (i = 0; i < dim; i++)
00668   {
00669     nzcnt = ur_inf[i].nzcnt;
00670     beg = ur_inf[i].rbeg;
00671     unzcnt += nzcnt;
00672     for (j = 0; j < nzcnt; j++)
00673     {
00674       dbl_EGlpNumSetToMaxAbs (umax, urcoef[beg + j]);
00675     }
00676   }
00677   dbl_EGlpNumZero (lmax);
00678   for (i = 0; i < dim; i++)
00679   {
00680     nzcnt = lc_inf[i].nzcnt;
00681     beg = lc_inf[i].cbeg;
00682     lnzcnt += nzcnt;
00683     for (j = 0; j < nzcnt; j++)
00684     {
00685       dbl_EGlpNumSetToMaxAbs (lmax, lccoef[beg + j]);
00686     }
00687   }
00688   dbl_EGlpNumZero (emax);
00689   for (i = 0; i < ecnt; i++)
00690   {
00691     nzcnt = er_inf[i].nzcnt;
00692     beg = er_inf[i].rbeg;
00693     enzcnt += nzcnt;
00694     for (j = 0; j < nzcnt; j++)
00695     {
00696       dbl_EGlpNumSetToMaxAbs (emax, ercoef[beg + j]);
00697     }
00698   }
00699   MESSAGE(0, "factor U %d nzs %.3e max L %d nzs %.3e max E %d nzs %.3e max",
00700           unzcnt, dbl_EGlpNumToLf (umax), lnzcnt, dbl_EGlpNumToLf (lmax), enzcnt,
00701           dbl_EGlpNumToLf (emax));
00702   fflush (stdout);
00703   dbl_EGlpNumClearVar (umax);
00704   dbl_EGlpNumClearVar (lmax);
00705   dbl_EGlpNumClearVar (emax);
00706 }
00707 #endif
00708 
00709 static void dbl_clear_work (
00710   dbl_factor_work * f)
00711 {
00712   int i;
00713   int dim = f->dim;
00714   double *work_coef = f->work_coef;
00715 
00716   for (i = 0; i < dim; i++)
00717   {
00718     dbl_EGlpNumZero (work_coef[i]);
00719   }
00720 }
00721 
00722 static void dbl_load_row (
00723   dbl_factor_work * f,
00724   int r)
00725 {
00726   double *prow_urcoef = f->urcoef + f->ur_inf[r].rbeg;
00727   int *prow_urindx = f->urindx + f->ur_inf[r].rbeg;
00728   int prow_nzcnt = f->ur_inf[r].nzcnt;
00729   double *work_coef = f->work_coef;
00730   int *work_indx = f->work_indx;
00731   int i;
00732   int j;
00733 
00734   for (i = 0; i < prow_nzcnt; i++)
00735   {
00736     j = prow_urindx[i];
00737     dbl_EGlpNumCopy (work_coef[j], prow_urcoef[i]);
00738     work_indx[j] = 1;
00739   }
00740 }
00741 
00742 static void dbl_clear_row (
00743   dbl_factor_work * f,
00744   int r)
00745 {
00746   int *prow_urindx = f->urindx + f->ur_inf[r].rbeg;
00747   int prow_nzcnt = f->ur_inf[r].nzcnt;
00748   double *work_coef = f->work_coef;
00749   int *work_indx = f->work_indx;
00750   int i;
00751   int j;
00752 
00753   for (i = 0; i < prow_nzcnt; i++)
00754   {
00755     j = prow_urindx[i];
00756     dbl_EGlpNumZero (work_coef[j]);
00757     work_indx[j] = 0;
00758   }
00759 }
00760 
00761 static int dbl_make_ur_space (
00762   dbl_factor_work * f,
00763   int space)
00764 {
00765   double *new_urcoef = 0;
00766   int *new_urindx = 0;
00767   int *new_urcind = 0;
00768   double *urcoef = f->urcoef;
00769   int *urindx = f->urindx;
00770   int *urcind = f->urcind;
00771   int minspace;
00772   dbl_ur_info *ur_inf = f->ur_inf;
00773   int dim = f->dim;
00774   int new_nzcnt = 0, old_nzcnt;
00775   int rbeg;
00776   int nzcnt;
00777   int i;
00778   int j;
00779   int rval;
00780 
00781   minspace = f->ur_space;
00782   nzcnt = space;
00783   for (i = 0; i < dim; i++)
00784     nzcnt += ur_inf[i].nzcnt;
00785   old_nzcnt = nzcnt;
00786   while (nzcnt * 2 >= minspace)
00787   {
00788     minspace = 1 + minspace * f->grow_mul;
00789   }
00790 
00791 #ifdef dbl_GROWTH_STATS
00792   printf ("dbl_make_ur_space growing from %d to %d...", f->ur_space, minspace);
00793   fflush (stdout);
00794 #endif
00795   new_urcoef = dbl_EGlpNumAllocArray (minspace);
00796   ILL_SAFE_MALLOC (new_urindx, minspace + 1, int);
00797 
00798   if (urcind)
00799   {
00800     ILL_SAFE_MALLOC (new_urcind, minspace, int);
00801   }
00802 
00803   if (urcind)
00804   {
00805     for (j = 0; j < dim; j++)
00806     {
00807       rbeg = ur_inf[j].rbeg;
00808       nzcnt = ur_inf[j].nzcnt;
00809       ur_inf[j].rbeg = new_nzcnt;
00810       for (i = 0; i < nzcnt; i++)
00811       {
00812         new_urindx[new_nzcnt] = urindx[rbeg + i];
00813         dbl_EGlpNumCopy (new_urcoef[new_nzcnt], urcoef[rbeg + i]);
00814         new_urcind[new_nzcnt] = urcind[rbeg + i];
00815         new_nzcnt++;
00816       }
00817     }
00818   }
00819   else
00820   {
00821     for (j = 0; j < dim; j++)
00822     {
00823       rbeg = ur_inf[j].rbeg;
00824       nzcnt = ur_inf[j].nzcnt;
00825       ur_inf[j].rbeg = new_nzcnt;
00826       for (i = 0; i < nzcnt; i++)
00827       {
00828         new_urindx[new_nzcnt] = urindx[rbeg + i];
00829         dbl_EGlpNumCopy (new_urcoef[new_nzcnt], urcoef[rbeg + i]);
00830         new_nzcnt++;
00831       }
00832     }
00833   }
00834 
00835   for (i = new_nzcnt; i < minspace; i++)
00836   {
00837     new_urindx[i] = -1;
00838   }
00839   new_urindx[minspace] = 0;
00840   dbl_EGlpNumFreeArray (f->urcoef);
00841   f->urcoef = new_urcoef;
00842   new_urcoef = 0;
00843 
00844   ILL_IFFREE (f->urindx, int);
00845 
00846   f->urindx = new_urindx;
00847   new_urindx = 0;
00848 
00849   ILL_IFFREE (f->urcind, int);
00850 
00851   f->urcind = new_urcind;
00852   new_urcind = 0;
00853 
00854   f->ur_freebeg = new_nzcnt;
00855   f->ur_space = minspace;
00856 
00857 #ifdef dbl_GROWTH_STATS
00858   MESSAGE (0,"%d/%d nonzeros", new_nzcnt, old_nzcnt);
00859   dbl_dump_factor_stats (f);
00860 #endif
00861 
00862   rval = 0;
00863 
00864 CLEANUP:
00865   ILL_IFFREE (new_urcoef, double);
00866   ILL_IFFREE (new_urindx, int);
00867   ILL_IFFREE (new_urcind, int);
00868 
00869   EG_RETURN (rval);
00870 }
00871 
00872 static int dbl_make_uc_space (
00873   dbl_factor_work * f,
00874   int space)
00875 {
00876   double *new_uccoef = 0;
00877   int *new_ucindx = 0;
00878   int *new_ucrind = 0;
00879   int uc_freebeg = f->uc_freebeg;
00880   double *uccoef = f->uccoef;
00881   int *ucindx = f->ucindx;
00882   int *ucrind = f->ucrind;
00883   int minspace = uc_freebeg + space;
00884   dbl_uc_info *uc_inf = f->uc_inf;
00885   int dim = f->dim;
00886   int new_nzcnt = 0;
00887   int cbeg;
00888   int nzcnt;
00889   int i;
00890   int j;
00891   int rval;
00892 
00893   minspace = f->uc_space;
00894   nzcnt = space;
00895   for( i = 0 ; i < dim ; i++) nzcnt += uc_inf[i].nzcnt;
00896   while(nzcnt*2 >= minspace)
00897   {
00898     minspace = 10 + (f->grow_mul * minspace);
00899   }
00900 
00901 #ifdef dbl_GROWTH_STATS
00902   MESSAGE (0,"dbl_make_uc_space growing from %d to %d...", f->uc_space, minspace);
00903 #endif
00904 
00905   ILL_SAFE_MALLOC (new_ucindx, minspace + 1, int);
00906 
00907   if (ucrind)
00908   {
00909     new_uccoef = dbl_EGlpNumAllocArray (minspace);
00910     ILL_SAFE_MALLOC (new_ucrind, minspace, int);
00911   }
00912 
00913   if (ucrind)
00914   {
00915     for (j = 0; j < dim; j++)
00916     {
00917       cbeg = uc_inf[j].cbeg;
00918       nzcnt = uc_inf[j].nzcnt;
00919       uc_inf[j].cbeg = new_nzcnt;
00920       for (i = 0; i < nzcnt; i++)
00921       {
00922         new_ucindx[new_nzcnt] = ucindx[cbeg + i];
00923         dbl_EGlpNumCopy (new_uccoef[new_nzcnt], uccoef[cbeg + i]);
00924         new_ucrind[new_nzcnt] = ucrind[cbeg + i];
00925         new_nzcnt++;
00926       }
00927     }
00928   }
00929   else
00930   {
00931     for (j = 0; j < dim; j++)
00932     {
00933       cbeg = uc_inf[j].cbeg;
00934       nzcnt = uc_inf[j].nzcnt;
00935       uc_inf[j].cbeg = new_nzcnt;
00936       for (i = 0; i < nzcnt; i++)
00937       {
00938         new_ucindx[new_nzcnt] = ucindx[cbeg + i];
00939         new_nzcnt++;
00940       }
00941     }
00942   }
00943 
00944   for (i = new_nzcnt; i < minspace; i++)
00945   {
00946     new_ucindx[i] = -1;
00947   }
00948   new_ucindx[minspace] = 0;
00949 
00950   dbl_EGlpNumFreeArray (f->uccoef);
00951   f->uccoef = new_uccoef;
00952   new_uccoef = 0;
00953 
00954   ILL_IFFREE (f->ucindx, int);
00955 
00956   f->ucindx = new_ucindx;
00957   new_ucindx = 0;
00958 
00959   ILL_IFFREE (f->ucrind, int);
00960 
00961   f->ucrind = new_ucrind;
00962   new_ucrind = 0;
00963 
00964   f->uc_freebeg = new_nzcnt;
00965   f->uc_space = minspace;
00966 
00967 #ifdef dbl_GROWTH_STATS
00968   MESSAGE (0,"%d nonzeros", new_nzcnt);
00969   dbl_dump_factor_stats (f);
00970 #endif
00971 
00972   rval = 0;
00973 
00974 CLEANUP:
00975   ILL_IFFREE (new_uccoef, double);
00976   ILL_IFFREE (new_ucindx, int);
00977   ILL_IFFREE (new_ucrind, int);
00978 
00979   EG_RETURN (rval);
00980 }
00981 
00982 static int dbl_make_lc_space (
00983   dbl_factor_work * f,
00984   int space)
00985 {
00986   double *new_lccoef = 0;
00987   int *new_lcindx = 0;
00988   int lc_freebeg = f->lc_freebeg;
00989   double *lccoef = f->lccoef;
00990   int *lcindx = f->lcindx;
00991   int minspace = lc_freebeg + space;
00992   int i;
00993   int rval;
00994 
00995   if (f->lc_space * f->grow_mul > minspace)
00996   {
00997     minspace = f->lc_space * f->grow_mul;
00998   }
00999 
01000 #ifdef dbl_GROWTH_STATS
01001   MESSAGE (0,"dbl_make_lc_space growing from %d to %d...", f->lc_space, minspace);
01002 #endif
01003 
01004   new_lccoef = dbl_EGlpNumAllocArray (minspace);
01005   ILL_SAFE_MALLOC (new_lcindx, minspace, int);
01006 
01007   for (i = 0; i < lc_freebeg; i++)
01008   {
01009     dbl_EGlpNumCopy (new_lccoef[i], lccoef[i]);
01010     new_lcindx[i] = lcindx[i];
01011   }
01012 
01013   dbl_EGlpNumFreeArray (lccoef);
01014   f->lccoef = new_lccoef;
01015   new_lccoef = 0;
01016 
01017   ILL_IFFREE (lcindx, int);
01018 
01019   f->lcindx = new_lcindx;
01020   new_lcindx = 0;
01021 
01022   f->lc_space = minspace;
01023 
01024 #ifdef dbl_GROWTH_STATS
01025   dbl_dump_factor_stats (f);
01026 #endif
01027 
01028   rval = 0;
01029 
01030 CLEANUP:
01031   ILL_IFFREE (new_lccoef, double);
01032   ILL_IFFREE (new_lcindx, int);
01033 
01034   EG_RETURN (rval);
01035 }
01036 
01037 static void dbl_set_col_nz (
01038   dbl_factor_work * f,
01039   int c)
01040 {
01041   dbl_uc_info *uc_inf = f->uc_inf;
01042   int nzcnt = uc_inf[c].nzcnt;
01043   int max_k = f->max_k;
01044   int dim = f->dim;
01045 
01046   if (uc_inf[c].next >= 0)
01047   {
01048     uc_inf[uc_inf[c].next].prev = uc_inf[c].prev;
01049     uc_inf[uc_inf[c].prev].next = uc_inf[c].next;
01050 
01051     if (nzcnt >= max_k)
01052       nzcnt = max_k;
01053     uc_inf[c].next = uc_inf[dim + nzcnt].next;
01054     uc_inf[c].prev = dim + nzcnt;
01055     uc_inf[dim + nzcnt].next = c;
01056     uc_inf[uc_inf[c].next].prev = c;
01057   }
01058 }
01059 
01060 static void dbl_set_row_nz (
01061   dbl_factor_work * f,
01062   int r)
01063 {
01064   dbl_ur_info *ur_inf = f->ur_inf;
01065   int nzcnt = ur_inf[r].pivcnt;
01066   int max_k = f->max_k;
01067   int dim = f->dim;
01068 
01069   if (ur_inf[r].next >= 0)
01070   {
01071     ur_inf[ur_inf[r].next].prev = ur_inf[r].prev;
01072     ur_inf[ur_inf[r].prev].next = ur_inf[r].next;
01073 
01074     if (nzcnt >= max_k)
01075       nzcnt = max_k;
01076     ur_inf[r].next = ur_inf[dim + nzcnt].next;
01077     ur_inf[r].prev = dim + nzcnt;
01078     ur_inf[dim + nzcnt].next = r;
01079     ur_inf[ur_inf[r].next].prev = r;
01080   }
01081 }
01082 
01083 static void dbl_remove_col_nz (
01084   dbl_factor_work * f,
01085   int r,
01086   int c)
01087 {
01088   dbl_uc_info *uc_inf = f->uc_inf;
01089   int *ucindx = f->ucindx + uc_inf[c].cbeg;
01090   int nzcnt = uc_inf[c].nzcnt;
01091   int i;
01092 
01093   for (i = 0; i < nzcnt; i++)
01094   {
01095     if (ucindx[i] == r)
01096     {
01097       --nzcnt;
01098       ucindx[i] = ucindx[nzcnt];
01099       ucindx[nzcnt] = -1;
01100       break;
01101     }
01102   }
01103   uc_inf[c].nzcnt = nzcnt;
01104 
01105   dbl_set_col_nz (f, c);
01106 }
01107 
01108 static void dbl_remove_row_nz (
01109   dbl_factor_work * f,
01110   int r,
01111   int c)
01112 {
01113   dbl_ur_info *ur_inf = f->ur_inf;
01114   int *urindx = f->urindx + ur_inf[r].rbeg;
01115   double *urcoef = f->urcoef + ur_inf[r].rbeg;
01116   int pivcnt = ur_inf[r].pivcnt;
01117   double max;
01118   int tind;
01119   double tcoef;
01120   int i;
01121 
01122   dbl_EGlpNumInitVar (tcoef);
01123   dbl_EGlpNumInitVar (max);
01124   dbl_EGlpNumZero (max);
01125 
01126   for (i = 0; i < pivcnt; i++)
01127   {
01128     if (urindx[i] == c)
01129     {
01130       --pivcnt;
01131       dbl_ILL_SWAP (urindx[i], urindx[pivcnt], tind);
01132       dbl_EGLPNUM_SWAP (urcoef[i], urcoef[pivcnt], tcoef);
01133       --i;
01134     }
01135     else
01136     {
01137       dbl_EGlpNumSetToMaxAbs (max, urcoef[i]);
01138     }
01139   }
01140   ur_inf[r].pivcnt = pivcnt;
01141   dbl_EGlpNumCopy (ur_inf[r].max, max);
01142   dbl_set_row_nz (f, r);
01143   dbl_EGlpNumClearVar (max);
01144   dbl_EGlpNumClearVar (tcoef);
01145 }
01146 
01147 static int dbl_add_col_nz (
01148   dbl_factor_work * f,
01149   int r,
01150   int c)
01151 {
01152   dbl_uc_info *uc_inf = f->uc_inf;
01153   int cbeg = uc_inf[c].cbeg;
01154   int nzcnt = uc_inf[c].nzcnt;
01155   int uc_freebeg = f->uc_freebeg;
01156   int *ucindx = f->ucindx;
01157   int i;
01158   int rval = 0;
01159 
01160   if (uc_inf[c].next == -1)
01161   {
01162     return 0;
01163   }
01164 
01165   if (ucindx[cbeg + nzcnt] == -1)
01166   {
01167     ucindx[cbeg + nzcnt] = r;
01168     uc_inf[c].nzcnt++;
01169     if (nzcnt + cbeg == uc_freebeg)
01170     {
01171       f->uc_freebeg = uc_freebeg + 1;
01172     }
01173   }
01174   else
01175   {
01176     if (uc_freebeg + nzcnt + 1 >= f->uc_space)
01177     {
01178       rval = dbl_make_uc_space (f, nzcnt + 1);
01179       CHECKRVALG (rval, CLEANUP);
01180       uc_freebeg = f->uc_freebeg;
01181       cbeg = uc_inf[c].cbeg;
01182       ucindx = f->ucindx;
01183     }
01184     for (i = 0; i < nzcnt; i++)
01185     {
01186       ucindx[uc_freebeg + i] = ucindx[cbeg + i];
01187       ucindx[cbeg + i] = -1;
01188     }
01189     ucindx[uc_freebeg + nzcnt] = r;
01190     uc_inf[c].cbeg = uc_freebeg;
01191     uc_inf[c].nzcnt++;
01192     f->uc_freebeg = uc_freebeg + nzcnt + 1;
01193   }
01194 
01195   dbl_set_col_nz (f, c);
01196 CLEANUP:
01197   EG_RETURN (rval);
01198 }
01199 
01200 static void dbl_disable_col (
01201   dbl_factor_work * f,
01202   int c)
01203 {
01204   dbl_uc_info *uc_inf = f->uc_inf;
01205 
01206   if (uc_inf[c].next >= 0)
01207   {
01208     uc_inf[uc_inf[c].next].prev = uc_inf[c].prev;
01209     uc_inf[uc_inf[c].prev].next = uc_inf[c].next;
01210 
01211     uc_inf[c].next = -2;
01212     uc_inf[c].prev = -2;
01213   }
01214 }
01215 
01216 static void dbl_remove_col (
01217   dbl_factor_work * f,
01218   int c)
01219 {
01220   dbl_uc_info *uc_inf = f->uc_inf;
01221   int cbeg = uc_inf[c].cbeg;
01222   int nzcnt = uc_inf[c].nzcnt;
01223   int *ucindx = f->ucindx;
01224   int i;
01225 
01226   for (i = 0; i < nzcnt; i++)
01227   {
01228     ucindx[cbeg + i] = -1;
01229   }
01230   uc_inf[c].cbeg = 0;
01231   uc_inf[c].nzcnt = 0;
01232 
01233   if (uc_inf[c].next >= 0)
01234   {
01235     uc_inf[uc_inf[c].next].prev = uc_inf[c].prev;
01236     uc_inf[uc_inf[c].prev].next = uc_inf[c].next;
01237 
01238     uc_inf[c].next = -1;
01239     uc_inf[c].prev = -1;
01240   }
01241 }
01242 
01243 static void dbl_remove_row (
01244   dbl_factor_work * f,
01245   int r)
01246 {
01247   dbl_ur_info *ur_inf = f->ur_inf;
01248 
01249   if (ur_inf[r].next >= 0)
01250   {
01251     ur_inf[ur_inf[r].next].prev = ur_inf[r].prev;
01252     ur_inf[ur_inf[r].prev].next = ur_inf[r].next;
01253 
01254     ur_inf[r].next = -1;
01255     ur_inf[r].prev = -1;
01256   }
01257 }
01258 
01259 static void dbl_find_coef (
01260   dbl_factor_work * f,
01261   int r,
01262   int c,
01263   double * coef)
01264 {
01265   double *prow_urcoef = f->urcoef + f->ur_inf[r].rbeg;
01266   int *prow_urindx = f->urindx + f->ur_inf[r].rbeg;
01267   int i;
01268   int prow_nzcnt = f->ur_inf[r].nzcnt;
01269 
01270   dbl_EGlpNumZero (*coef);
01271   for (i = 0; i < prow_nzcnt; i++)
01272   {
01273     if (prow_urindx[i] == c)
01274     {
01275       dbl_EGlpNumCopy (*coef, prow_urcoef[i]);
01276       return;
01277     }
01278   }
01279   fprintf (stderr, "Coefficient not found\n");
01280   return;
01281 }
01282 
01283 static int dbl_elim_row (
01284   dbl_factor_work * f,
01285   int elim_r,
01286   int r,
01287   int c,
01288   double * p_pivot_coef)
01289 {
01290   dbl_ur_info *ur_inf = f->ur_inf;
01291   double *work_coef = f->work_coef;
01292   int *work_indx = f->work_indx;
01293   double *urcoef = f->urcoef;
01294   int *urindx = f->urindx;
01295   int prow_beg = ur_inf[r].rbeg;
01296   int prow_nzcnt = ur_inf[r].nzcnt;
01297   int prow_pivcnt = ur_inf[r].pivcnt;
01298   int fill = ur_inf[elim_r].nzcnt;
01299   int cancel = 0;
01300   double max;
01301   int erow_beg;
01302   int erow_nzcnt;
01303   int erow_pivcnt;
01304   double x;
01305   int i;
01306   int j;
01307   int rval = 0;
01308   double elim_coef;
01309 
01310   dbl_EGlpNumInitVar (max);
01311   dbl_EGlpNumInitVar (x);
01312   dbl_EGlpNumInitVar (elim_coef);
01313   dbl_EGlpNumZero (max);
01314   dbl_find_coef (f, r, c, &elim_coef);
01315   dbl_EGlpNumDivTo (elim_coef, work_coef[c]);
01316   dbl_EGlpNumCopy (*p_pivot_coef, elim_coef);
01317 
01318   for (i = 0; i < prow_nzcnt; i++)
01319   {
01320     j = urindx[prow_beg + i];
01321     if (work_indx[j] == 1)
01322     {
01323       dbl_EGlpNumCopy (x, urcoef[prow_beg + i]);
01324       dbl_EGlpNumSubInnProdTo (x, elim_coef, work_coef[j]);
01325       if ((!(dbl_EGlpNumIsNeqZero (x, f->fzero_tol))) || j == c)
01326       {
01327         cancel++;
01328         if (j != c)
01329         {
01330           dbl_remove_col_nz (f, r, j);
01331         }
01332         if (i < prow_pivcnt)
01333         {
01334           prow_pivcnt--;
01335           prow_nzcnt--;
01336           urindx[prow_beg + i] = urindx[prow_beg + prow_pivcnt];
01337           dbl_EGlpNumCopy (urcoef[prow_beg + i], urcoef[prow_beg + prow_pivcnt]);
01338           if (prow_pivcnt != prow_nzcnt)
01339           {
01340             urindx[prow_beg + prow_pivcnt] = urindx[prow_beg + prow_nzcnt];
01341             dbl_EGlpNumCopy (urcoef[prow_beg + prow_pivcnt],
01342                          urcoef[prow_beg + prow_nzcnt]);
01343           }
01344         }
01345         else
01346         {
01347           prow_nzcnt--;
01348           urindx[prow_beg + i] = urindx[prow_beg + prow_nzcnt];
01349           dbl_EGlpNumCopy (urcoef[prow_beg + i], urcoef[prow_beg + prow_nzcnt]);
01350         }
01351         urindx[prow_beg + prow_nzcnt] = -1;
01352         i--;
01353       }
01354       else
01355       {
01356         dbl_EGlpNumCopy (urcoef[prow_beg + i], x);
01357         if (i < prow_pivcnt)
01358         {
01359           dbl_EGlpNumSetToMaxAbs (max, x);
01360         }
01361       }
01362       work_indx[j] = 0;
01363       fill--;
01364     }
01365     else
01366     {
01367       if (i < prow_pivcnt)
01368       {
01369         dbl_EGlpNumSetToMaxAbs (max, urcoef[prow_beg + i]);
01370       }
01371     }
01372   }
01373 
01374   if (fill > 0)
01375   {
01376     ur_inf[r].nzcnt = prow_nzcnt;
01377     ur_inf[r].pivcnt = prow_pivcnt;
01378     if (fill > cancel)
01379     {
01380       int ur_freebeg = f->ur_freebeg;
01381 
01382       if (ur_freebeg + prow_nzcnt + fill >= f->ur_space)
01383       {
01384         rval = dbl_make_ur_space (f, prow_nzcnt + fill);
01385         CHECKRVALG (rval, CLEANUP);
01386         urcoef = f->urcoef;
01387         urindx = f->urindx;
01388         ur_freebeg = f->ur_freebeg;
01389         prow_beg = f->ur_inf[r].rbeg;
01390       }
01391       for (i = 0; i < prow_nzcnt; i++)
01392       {
01393         urindx[ur_freebeg + i] = urindx[prow_beg + i];
01394         dbl_EGlpNumCopy (urcoef[ur_freebeg + i], urcoef[prow_beg + i]);
01395         urindx[prow_beg + i] = -1;
01396       }
01397       ur_inf[r].rbeg = ur_freebeg;
01398       f->ur_freebeg = ur_freebeg + prow_nzcnt + fill;
01399       prow_beg = ur_freebeg;
01400     }
01401 
01402     erow_beg = ur_inf[elim_r].rbeg;
01403     erow_nzcnt = ur_inf[elim_r].nzcnt;
01404     erow_pivcnt = ur_inf[elim_r].pivcnt;
01405 
01406     for (i = 0; i < erow_pivcnt; i++)
01407     {
01408       j = urindx[erow_beg + i];
01409       if (work_indx[j] == 1)
01410       {
01411         dbl_EGlpNumCopyNeg (x, elim_coef);
01412         dbl_EGlpNumMultTo (x, urcoef[erow_beg + i]);
01413         if (dbl_EGlpNumIsNeqZero (x, f->fzero_tol))
01414         {
01415           rval = dbl_add_col_nz (f, r, j);
01416           CHECKRVALG (rval, CLEANUP);
01417           if (prow_pivcnt != prow_nzcnt)
01418           {
01419             urindx[prow_beg + prow_nzcnt] = urindx[prow_beg + prow_pivcnt];
01420             dbl_EGlpNumCopy (urcoef[prow_beg + prow_nzcnt],
01421                          urcoef[prow_beg + prow_pivcnt]);
01422           }
01423           urindx[prow_beg + prow_pivcnt] = j;
01424           dbl_EGlpNumCopy (urcoef[prow_beg + prow_pivcnt], x);
01425           dbl_EGlpNumSetToMaxAbs (max, x);
01426           prow_pivcnt++;
01427           prow_nzcnt++;
01428         }
01429       }
01430       else
01431       {
01432         work_indx[j] = 1;
01433       }
01434     }
01435     for (i = erow_pivcnt; i < erow_nzcnt; i++)
01436     {
01437       j = urindx[erow_beg + i];
01438       if (work_indx[j] == 1)
01439       {
01440         dbl_EGlpNumCopyNeg (x, elim_coef);
01441         dbl_EGlpNumMultTo (x, urcoef[erow_beg + i]);
01442         if (dbl_EGlpNumIsNeqZero (x, f->fzero_tol))
01443         {
01444           rval = dbl_add_col_nz (f, r, j);
01445           CHECKRVALG (rval, CLEANUP);
01446           urindx[prow_beg + prow_nzcnt] = j;
01447           dbl_EGlpNumCopy (urcoef[prow_beg + prow_nzcnt], x);
01448           prow_nzcnt++;
01449         }
01450       }
01451       else
01452       {
01453         work_indx[j] = 1;
01454       }
01455     }
01456   }
01457   else
01458   {
01459     erow_nzcnt = ur_inf[elim_r].nzcnt;
01460     erow_beg = ur_inf[elim_r].rbeg;
01461     for (i = 0; i < erow_nzcnt; i++)
01462     {
01463       j = urindx[erow_beg + i];
01464       work_indx[j] = 1;
01465     }
01466   }
01467 
01468   ur_inf[r].nzcnt = prow_nzcnt;
01469   ur_inf[r].pivcnt = prow_pivcnt;
01470   dbl_EGlpNumCopy (ur_inf[r].max, max);
01471 
01472   dbl_set_row_nz (f, r);
01473 CLEANUP:
01474   dbl_EGlpNumClearVar (elim_coef);
01475   dbl_EGlpNumClearVar (x);
01476   dbl_EGlpNumClearVar (max);
01477   EG_RETURN (rval);
01478 }
01479 
01480 #define dbl_SETPERM(f,s,r,c) {                    \
01481         f->rperm[f->rrank[r]] = f->rperm[s];  \
01482         f->rrank[f->rperm[s]] = f->rrank[r];  \
01483         f->rperm[s] = r;                      \
01484         f->rrank[r] = s;                      \
01485                                               \
01486         f->cperm[f->crank[c]] = f->cperm[s];  \
01487         f->crank[f->cperm[s]] = f->crank[c];  \
01488         f->cperm[s] = c;                      \
01489         f->crank[c] = s;                      \
01490 }
01491 
01492 static int dbl_elim (
01493   dbl_factor_work * f,
01494   int r,
01495   int c)
01496 {
01497   dbl_uc_info *uc_inf = f->uc_inf;
01498   dbl_ur_info *ur_inf = f->ur_inf;
01499   dbl_lc_info *lc_inf = f->lc_inf;
01500   int *urindx;
01501   int *ucindx;
01502   int *lcindx;
01503   double *urcoef;
01504   double *lccoef;
01505   double pivot_coef;
01506   int nzcnt;
01507   int lc_freebeg;
01508   int s = f->stage;
01509   int i;
01510   int j;
01511   int rval = 0;
01512 
01513   dbl_EGlpNumInitVar (pivot_coef);
01514 
01515   if (uc_inf[c].nzcnt == 1)
01516   {
01517     /* col singleton */
01518     dbl_SETPERM (f, s, r, c);
01519 
01520     lc_inf[s].cbeg = -1;
01521     lc_inf[s].c = r;
01522     lc_inf[s].nzcnt = 0;
01523     f->stage++;
01524 
01525     urindx = f->urindx + ur_inf[r].rbeg;
01526     urcoef = f->urcoef + ur_inf[r].rbeg;
01527     nzcnt = ur_inf[r].nzcnt;
01528     for (i = 0; i < nzcnt; i++)
01529     {
01530       j = urindx[i];
01531       dbl_remove_col_nz (f, r, j);
01532       if (j == c)
01533       {
01534         urindx[i] = urindx[0];
01535         urindx[0] = c;
01536         dbl_EGLPNUM_SWAP (urcoef[0], urcoef[i], pivot_coef);
01537       }
01538     }
01539     dbl_remove_row (f, r);
01540     dbl_remove_col (f, c);
01541   }
01542   else if (ur_inf[r].nzcnt == 1)
01543   {
01544     /* row singleton */
01545     --(f->nstages);
01546     dbl_SETPERM (f, f->nstages, r, c);
01547 
01548     lc_inf[f->nstages].cbeg = -1;
01549     lc_inf[f->nstages].c = r;
01550     lc_inf[f->nstages].nzcnt = 0;
01551 
01552     ucindx = f->ucindx + uc_inf[c].cbeg;
01553     nzcnt = uc_inf[c].nzcnt;
01554     for (i = 0; i < nzcnt; i++)
01555     {
01556       j = ucindx[i];
01557       dbl_remove_row_nz (f, j, c);
01558     }
01559     dbl_remove_row (f, r);
01560     dbl_remove_col (f, c);
01561   }
01562   else
01563   {
01564     dbl_SETPERM (f, s, r, c);
01565     f->stage++;
01566 
01567     nzcnt = uc_inf[c].nzcnt;
01568     if (f->lc_freebeg + nzcnt >= f->lc_space)
01569     {
01570       rval = dbl_make_lc_space (f, nzcnt);
01571       CHECKRVALG (rval, CLEANUP);
01572     }
01573     lc_freebeg = f->lc_freebeg;
01574     lc_inf[s].cbeg = lc_freebeg;
01575     lc_inf[s].c = r;
01576     lcindx = f->lcindx;
01577     lccoef = f->lccoef;
01578     dbl_load_row (f, r);
01579     ucindx = f->ucindx + uc_inf[c].cbeg;
01580     for (i = 0; i < nzcnt; i++)
01581     {
01582       j = f->ucindx[uc_inf[c].cbeg + i];
01583       if (j != r)
01584       {
01585         rval = dbl_elim_row (f, r, j, c, &pivot_coef);
01586         CHECKRVALG (rval, CLEANUP);
01587         lcindx[lc_freebeg] = j;
01588         dbl_EGlpNumCopy (lccoef[lc_freebeg], pivot_coef);
01589         lc_freebeg++;
01590 #ifdef dbl_TRACK_FACTOR
01591         dbl_EGlpNumSetToMaxAbs (f->maxelem_factor, pivot_coef);
01592         if (dbl_EGlpNumIsLess (f->maxelem_factor, ur_inf[r].max))
01593           dbl_EGlpNumCopy (f->maxelem_factor, ur_inf[r].max);
01594 #endif /* dbl_TRACK_FACTOR */
01595       }
01596     }
01597     lc_inf[s].nzcnt = lc_freebeg - lc_inf[s].cbeg;
01598     f->lc_freebeg = lc_freebeg;
01599 
01600     dbl_clear_row (f, r);
01601 
01602     urindx = f->urindx + ur_inf[r].rbeg;
01603     urcoef = f->urcoef + ur_inf[r].rbeg;
01604     nzcnt = ur_inf[r].nzcnt;
01605     for (i = 0; i < nzcnt; i++)
01606     {
01607       j = urindx[i];
01608       dbl_remove_col_nz (f, r, j);
01609       if (j == c)
01610       {
01611         urindx[i] = urindx[0];
01612         urindx[0] = c;
01613         dbl_EGLPNUM_SWAP (urcoef[0], urcoef[i], pivot_coef);
01614       }
01615     }
01616     dbl_remove_row (f, r);
01617     dbl_remove_col (f, c);
01618   }
01619 CLEANUP:
01620   dbl_EGlpNumClearVar (pivot_coef);
01621   EG_RETURN (rval);
01622 }
01623 
01624 static void dbl_find_pivot_column (
01625   dbl_factor_work * f,
01626   int c,
01627   int *p_r)
01628 {
01629   dbl_uc_info *uc_inf = f->uc_inf;
01630   dbl_ur_info *ur_inf = f->ur_inf;
01631   int *ucindx = f->ucindx;
01632   int nzcnt = uc_inf[c].nzcnt;
01633   int cbeg = uc_inf[c].cbeg;
01634   double num_tmp[2];
01635   int bestnz = -1;
01636   int i;
01637   int r;
01638 
01639   dbl_EGlpNumInitVar (num_tmp[0]);
01640   dbl_EGlpNumInitVar (num_tmp[1]);
01641 
01642   *p_r = -1;
01643   for (i = 0; i < nzcnt; i++)
01644   {
01645     r = ucindx[cbeg + i];
01646     if((bestnz == -1 || ur_inf[r].pivcnt < bestnz))
01647     {
01648       dbl_find_coef (f, r, c, num_tmp);
01649       if(dbl_EGlpNumIsLessZero(num_tmp[0]))
01650         dbl_EGlpNumSign (num_tmp[0]);
01651       dbl_EGlpNumCopy (num_tmp[1], f->partial_cur);
01652       dbl_EGlpNumMultTo (num_tmp[1], ur_inf[r].max);
01653       if(dbl_EGlpNumIsLeq (num_tmp[1], num_tmp[0]))
01654       {
01655         bestnz = ur_inf[r].pivcnt;
01656         *p_r = r;
01657       }
01658     }
01659   }
01660   dbl_EGlpNumClearVar (num_tmp[0]);
01661   dbl_EGlpNumClearVar (num_tmp[1]);
01662 }
01663 
01664 static void dbl_find_pivot_row (
01665   dbl_factor_work * f,
01666   int r,
01667   int *p_c)
01668 {
01669   dbl_uc_info *uc_inf = f->uc_inf;
01670   dbl_ur_info *ur_inf = f->ur_inf;
01671   int *urindx = f->urindx;
01672   double *urcoef = f->urcoef;
01673   int pivcnt = ur_inf[r].pivcnt;
01674   int rbeg = ur_inf[r].rbeg;
01675   double thresh[2];
01676   int bestnz = -1;
01677   int i;
01678   int c;
01679 
01680   dbl_EGlpNumInitVar (thresh[0]);
01681   dbl_EGlpNumInitVar (thresh[1]);
01682   dbl_EGlpNumCopy (thresh[0], f->partial_cur);
01683   dbl_EGlpNumMultTo (thresh[0], ur_inf[r].max);
01684   *p_c = -1;
01685   for (i = 0; i < pivcnt; i++)
01686   {
01687     c = urindx[rbeg + i];
01688     if ((bestnz == -1 || uc_inf[c].nzcnt < bestnz))
01689     {
01690       dbl_EGlpNumCopyAbs (thresh[1], urcoef[rbeg + i]);
01691       if(dbl_EGlpNumIsLeq (thresh[0], thresh[1]))
01692       {
01693         bestnz = uc_inf[c].nzcnt;
01694         *p_c = c;
01695       }
01696     }
01697   }
01698   dbl_EGlpNumClearVar (thresh[0]);
01699   dbl_EGlpNumClearVar (thresh[1]);
01700 }
01701 
01702 static int dbl_find_pivot (
01703   dbl_factor_work * f,
01704   int *p_r,
01705   int *p_c)
01706 {
01707   dbl_uc_info *uc_inf = f->uc_inf;
01708   dbl_ur_info *ur_inf = f->ur_inf;
01709   int dim = f->dim;
01710   int max_k = f->max_k;
01711   int p = f->p;
01712   int c;
01713   int r;
01714   int mm = 0;
01715   int n = 0;
01716   int m;
01717   int k = 2;
01718 
01719   if (uc_inf[dim + 1].next != dim + 1)
01720   {
01721     c = uc_inf[dim + 1].next;
01722     r = f->ucindx[uc_inf[c].cbeg];
01723     *p_c = c;
01724     *p_r = r;
01725     return 0;
01726   }
01727   else if (ur_inf[dim + 1].next != dim + 1)
01728   {
01729     r = ur_inf[dim + 1].next;
01730     c = f->urindx[ur_inf[r].rbeg];
01731     *p_c = c;
01732     *p_r = r;
01733     return 0;
01734   }
01735   *p_r = -1;
01736   *p_c = -1;
01737   for (; k <= max_k && (mm == 0 || mm > (k - 1) * (k - 1)); k++)
01738   {
01739     if (uc_inf[dim + k].next != dim + k)
01740     {
01741       for (c = uc_inf[dim + k].next; c != dim + k; c = uc_inf[c].next)
01742       {
01743         dbl_find_pivot_column (f, c, &r);
01744         if (r >= 0)
01745         {
01746           m = (uc_inf[c].nzcnt - 1) * (ur_inf[r].pivcnt - 1);
01747           if (mm == 0 || m < mm)
01748           {
01749             mm = m;
01750             *p_c = c;
01751             *p_r = r;
01752             if (mm <= (k - 1) * (k - 1))
01753             {
01754               return 0;
01755             }
01756           }
01757         }
01758         else
01759         {
01760           c = uc_inf[c].prev;
01761           dbl_disable_col (f, uc_inf[c].next);
01762         }
01763         n++;
01764         if (n >= p && mm != 0)
01765         {
01766           return 0;
01767         }
01768       }
01769     }
01770 
01771     if (ur_inf[dim + k].next != dim + k)
01772     {
01773       for (r = ur_inf[dim + k].next; r != dim + k; r = ur_inf[r].next)
01774       {
01775         dbl_find_pivot_row (f, r, &c);
01776         if (c >= 0)
01777         {
01778           m = (uc_inf[c].nzcnt - 1) * (ur_inf[r].pivcnt - 1);
01779           if (mm == 0 || m < mm)
01780           {
01781             mm = m;
01782             *p_c = c;
01783             *p_r = r;
01784             if (mm <= k * (k - 1))
01785             {
01786               return 0;
01787             }
01788           }
01789         }
01790         n++;
01791         if (n >= p && mm != 0)
01792         {
01793           return 0;
01794         }
01795       }
01796     }
01797   }
01798   if (mm != 0)
01799   {
01800     return 0;
01801   }
01802   else
01803   {
01804     //fprintf (stderr, "No acceptable pivot found\n");
01805     return E_NO_PIVOT;
01806   }
01807 }
01808 
01809 static int dbl_create_factor_space (
01810   dbl_factor_work * f)
01811 {
01812   dbl_uc_info *uc_inf = f->uc_inf;
01813   dbl_ur_info *ur_inf = f->ur_inf;
01814   int dim = f->dim;
01815   int nzcnt;
01816   int i;
01817   int rval;
01818 
01819   nzcnt = 0;
01820   for (i = 0; i < dim; i++)
01821   {
01822     nzcnt += ur_inf[i].nzcnt;
01823   }
01824 
01825   if (f->ucindx == 0)
01826   {
01827     f->uc_space = nzcnt * f->uc_space_mul;
01828     ILL_SAFE_MALLOC (f->ucindx, f->uc_space + 1, int);
01829   }
01830 
01831   if (f->urindx == 0 || f->urcoef == 0)
01832   {
01833     ILL_IFFREE (f->urindx, int);
01834 
01835     dbl_EGlpNumFreeArray (f->urcoef);
01836     f->ur_space = nzcnt * f->ur_space_mul;
01837     ILL_SAFE_MALLOC (f->urindx, f->ur_space + 1, int);
01838 
01839     f->urcoef = dbl_EGlpNumAllocArray (f->ur_space);
01840   }
01841 
01842   if (f->lcindx == 0 || f->lccoef == 0)
01843   {
01844     ILL_IFFREE (f->lcindx, int);
01845 
01846     dbl_EGlpNumFreeArray (f->lccoef);
01847     f->lc_space = nzcnt * f->lc_space_mul;
01848     ILL_SAFE_MALLOC (f->lcindx, f->lc_space, int);
01849 
01850     f->lccoef = dbl_EGlpNumAllocArray (f->lc_space);
01851   }
01852 
01853   nzcnt = 0;
01854   for (i = 0; i < dim; i++)
01855   {
01856     ur_inf[i].rbeg = nzcnt;
01857     nzcnt += ur_inf[i].nzcnt;
01858     ur_inf[i].nzcnt = ur_inf[i].rbeg;
01859   }
01860   f->ur_freebeg = nzcnt;
01861 
01862   nzcnt = 0;
01863   for (i = 0; i < dim; i++)
01864   {
01865     uc_inf[i].cbeg = nzcnt;
01866     nzcnt += uc_inf[i].nzcnt;
01867     uc_inf[i].nzcnt = uc_inf[i].cbeg;
01868   }
01869   f->uc_freebeg = nzcnt;
01870 
01871   f->lc_freebeg = 0;
01872 
01873   rval = 0;
01874 CLEANUP:
01875   EG_RETURN (rval);
01876 }
01877 
01878 static int dbl_init_matrix (
01879   dbl_factor_work * f,
01880   int *basis,
01881   int *cbeg,
01882   int *clen,
01883   int *in_ucindx,
01884   double * in_uccoef)
01885 {
01886   dbl_uc_info *uc_inf = f->uc_inf;
01887   dbl_ur_info *ur_inf = f->ur_inf;
01888   int dim = f->dim;
01889   int max_k = f->max_k;
01890   int *ucindx;
01891   int *urindx;
01892   double *urcoef;
01893   int nzcnt;
01894   int beg;
01895   int i;
01896   int j;
01897   int r;
01898   int rval = 0;
01899   double v;
01900   double max;
01901 
01902   dbl_EGlpNumInitVar (v);
01903   dbl_EGlpNumInitVar (max);
01904 
01905   for (i = 0; i < dim; i++)
01906   {
01907     ur_inf[i].nzcnt = 0;
01908   }
01909   for (i = 0; i < dim; i++)
01910   {
01911     nzcnt = clen[basis[i]];
01912     beg = cbeg[basis[i]];
01913     uc_inf[i].nzcnt = nzcnt;
01914     for (j = 0; j < nzcnt; j++)
01915     {
01916       r = in_ucindx[beg + j];
01917       ur_inf[r].nzcnt++;
01918     }
01919   }
01920 
01921   rval = dbl_create_factor_space (f);
01922   CHECKRVALG (rval, CLEANUP);
01923 
01924   urindx = f->urindx;
01925   ucindx = f->ucindx;
01926   urcoef = f->urcoef;
01927 
01928   for (i = 0; i < dim; i++)
01929   {
01930     nzcnt = clen[basis[i]];
01931     beg = cbeg[basis[i]];
01932     for (j = 0; j < nzcnt; j++)
01933     {
01934       dbl_EGlpNumCopy (v, in_uccoef[beg + j]);
01935       if (!(dbl_EGlpNumIsNeqZero (v, f->fzero_tol)))
01936         continue;
01937       r = in_ucindx[beg + j];
01938       ucindx[uc_inf[i].nzcnt++] = r;
01939       urindx[ur_inf[r].nzcnt] = i;
01940       dbl_EGlpNumCopy (urcoef[ur_inf[r].nzcnt], v);
01941       ur_inf[r].nzcnt++;
01942     }
01943   }
01944 
01945   for (i = 0; i < dim; i++)
01946   {
01947     uc_inf[i].nzcnt -= uc_inf[i].cbeg;
01948     ur_inf[i].nzcnt -= ur_inf[i].rbeg;
01949   }
01950 
01951   j = f->uc_space;
01952   for (i = f->uc_freebeg; i < j; i++)
01953   {
01954     ucindx[i] = -1;
01955   }
01956   ucindx[j] = 0;
01957 
01958   j = f->ur_space;
01959   for (i = f->ur_freebeg; i < j; i++)
01960   {
01961     urindx[i] = -1;
01962   }
01963   urindx[j] = 0;
01964 
01965   for (i = 0; i < dim; i++)
01966   {
01967     nzcnt = ur_inf[i].nzcnt;
01968     ur_inf[i].pivcnt = nzcnt;
01969     beg = ur_inf[i].rbeg;
01970     dbl_EGlpNumZero (max);
01971     for (j = 0; j < nzcnt; j++)
01972     {
01973       dbl_EGlpNumSetToMaxAbs (max, urcoef[beg + j]);
01974     }
01975     dbl_EGlpNumCopy (ur_inf[i].max, max);
01976   }
01977 
01978   for (i = 0; i <= max_k; i++)
01979   {
01980     ur_inf[dim + i].next = dim + i;
01981     ur_inf[dim + i].prev = dim + i;
01982     uc_inf[dim + i].next = dim + i;
01983     uc_inf[dim + i].prev = dim + i;
01984   }
01985 
01986   for (i = 0; i < dim; i++)
01987   {
01988     nzcnt = uc_inf[i].nzcnt;
01989     if (nzcnt >= max_k)
01990       nzcnt = max_k;
01991     uc_inf[i].next = uc_inf[dim + nzcnt].next;
01992     uc_inf[i].prev = dim + nzcnt;
01993     uc_inf[dim + nzcnt].next = i;
01994     uc_inf[uc_inf[i].next].prev = i;
01995 
01996     nzcnt = ur_inf[i].pivcnt;
01997     if (nzcnt >= max_k)
01998       nzcnt = max_k;
01999     ur_inf[i].next = ur_inf[dim + nzcnt].next;
02000     ur_inf[i].prev = dim + nzcnt;
02001     ur_inf[dim + nzcnt].next = i;
02002     ur_inf[ur_inf[i].next].prev = i;
02003   }
02004 
02005 #ifdef dbl_TRACK_FACTOR
02006   dbl_EGlpNumZero (max);
02007   nzcnt = 0;
02008   for (i = 0; i < dim; i++)
02009   {
02010     if (dbl_EGlpNumIsLess (max, ur_inf[i].max))
02011       dbl_EGlpNumCopy (max, ur_inf[i].max);
02012     nzcnt += ur_inf[i].nzcnt;
02013   }
02014 
02015   dbl_EGlpNumCopy (f->maxelem_orig, max);
02016   f->nzcnt_orig = nzcnt;
02017   dbl_EGlpNumCopy (f->maxelem_factor, f->maxelem_orig);
02018   f->nzcnt_factor = f->nzcnt_orig;
02019 #endif /* dbl_TRACK_FACTOR */
02020 
02021   /* sentinal for column space */
02022   ucindx[f->uc_space] = 0;
02023 
02024   dbl_clear_work (f);
02025 
02026 CLEANUP:
02027   dbl_EGlpNumClearVar (max);
02028   dbl_EGlpNumClearVar (v);
02029   EG_RETURN (rval);
02030 }
02031 
02032 static int dbl_build_iteration_u_data (
02033   dbl_factor_work * f)
02034 {
02035   int dim = f->dim;
02036   dbl_ur_info *ur_inf = f->ur_inf;
02037   dbl_uc_info *uc_inf = f->uc_inf;
02038   double *uccoef = 0;
02039   int *ucindx = 0;
02040   int *urindx = f->urindx;
02041   double *urcoef = f->urcoef;
02042   int *ucrind = 0;
02043   int *urcind = 0;
02044   int nzcnt;
02045   int beg;
02046   int cbeg;
02047   int cnzcnt;
02048   int uc_space = f->uc_space;
02049   int er_space;
02050   int i;
02051   int j;
02052   int k;
02053   int rval;
02054 
02055   nzcnt = 0;
02056   for (i = 0; i < dim; i++)
02057   {
02058     nzcnt += ur_inf[i].nzcnt;
02059   }
02060 
02061 #ifdef dbl_TRACK_FACTOR
02062   f->nzcnt_factor = nzcnt;
02063 #endif /* dbl_TRACK_FACTOR */
02064 
02065   dbl_EGlpNumFreeArray (f->uccoef);
02066   uccoef = dbl_EGlpNumAllocArray (nzcnt);
02067   f->uccoef = uccoef;
02068 
02069   ILL_IFFREE (f->ucrind, int);
02070   ILL_SAFE_MALLOC (ucrind, nzcnt, int);
02071 
02072   f->ucrind = ucrind;
02073 
02074   ILL_IFFREE (f->urcind, int);
02075   ILL_SAFE_MALLOC (urcind, f->ur_space, int);
02076 
02077   f->urcind = urcind;
02078 
02079   if (uc_space < nzcnt)
02080   {
02081     ILL_IFFREE (f->ucindx, int);
02082     ILL_SAFE_MALLOC (f->ucindx, nzcnt + 1, int);
02083   }
02084   f->uc_space = nzcnt;
02085   uc_space = nzcnt;
02086   ucindx = f->ucindx;
02087 
02088   for (i = 0; i < dim; i++)
02089   {
02090     uc_inf[i].nzcnt = 0;
02091   }
02092 
02093   for (i = 0; i < dim; i++)
02094   {
02095     nzcnt = ur_inf[i].nzcnt;
02096     beg = ur_inf[i].rbeg;
02097     for (j = 0; j < nzcnt; j++)
02098     {
02099       uc_inf[urindx[beg + j]].nzcnt++;
02100     }
02101     ur_inf[i].delay = 0;
02102   }
02103 
02104   nzcnt = 0;
02105   for (i = 0; i < dim; i++)
02106   {
02107     uc_inf[i].cbeg = nzcnt;
02108     nzcnt += uc_inf[i].nzcnt;
02109     uc_inf[i].nzcnt = 0;
02110     uc_inf[i].delay = 0;
02111   }
02112 
02113   f->uc_freebeg = nzcnt;
02114   for (i = nzcnt; i < uc_space; i++)
02115   {
02116     ucindx[i] = -1;
02117   }
02118   ucindx[uc_space] = 0;
02119 
02120   for (i = 0; i < dim; i++)
02121   {
02122     nzcnt = ur_inf[i].nzcnt;
02123     beg = ur_inf[i].rbeg;
02124     k = urindx[beg];
02125     cbeg = uc_inf[k].cbeg;
02126     cnzcnt = uc_inf[k].nzcnt;
02127     if (cnzcnt != 0)
02128     {
02129       ucindx[cbeg + cnzcnt] = ucindx[cbeg];
02130       dbl_EGlpNumCopy (uccoef[cbeg + cnzcnt], uccoef[cbeg]);
02131       ucrind[cbeg + cnzcnt] = ucrind[cbeg];
02132       urcind[ur_inf[ucindx[cbeg]].rbeg + ucrind[cbeg]] = cnzcnt;
02133     }
02134     ucindx[cbeg] = i;
02135     dbl_EGlpNumCopy (uccoef[cbeg], urcoef[beg]);
02136     ucrind[cbeg] = 0;
02137     urcind[beg] = 0;
02138     uc_inf[k].nzcnt = cnzcnt + 1;
02139     for (j = 1; j < nzcnt; j++)
02140     {
02141       k = urindx[beg + j];
02142       cbeg = uc_inf[k].cbeg;
02143       cnzcnt = uc_inf[k].nzcnt;
02144       ucindx[cbeg + cnzcnt] = i;
02145       dbl_EGlpNumCopy (uccoef[cbeg + cnzcnt], urcoef[beg + j]);
02146       ucrind[cbeg + cnzcnt] = j;
02147       urcind[beg + j] = cnzcnt;
02148       uc_inf[k].nzcnt++;
02149     }
02150   }
02151 
02152   for (i = 0; i < dim; i++)
02153   {
02154     f->rrank[f->rperm[i]] = i;
02155   }
02156 
02157   nzcnt = f->ur_space;
02158 
02159   for (i = f->ur_freebeg; i < nzcnt; i++)
02160   {
02161     urindx[i] = -1;
02162   }
02163   urindx[nzcnt] = 0;
02164 
02165   dbl_clear_work (f);
02166 
02167   er_space = f->er_space_mul * f->etamax;
02168   ILL_SAFE_MALLOC (f->er_inf, f->etamax, dbl_er_info);
02169   ILL_SAFE_MALLOC (f->erindx, er_space, int);
02170 
02171   f->ercoef = dbl_EGlpNumAllocArray (er_space);
02172   f->etacnt = 0;
02173   f->er_freebeg = 0;
02174   f->er_space = er_space;
02175 
02176   rval = 0;
02177 
02178 CLEANUP:
02179   EG_RETURN (rval);
02180 }
02181 
02182 static int dbl_build_iteration_l_data (
02183   dbl_factor_work * f)
02184 {
02185   int dim = f->dim;
02186   dbl_lc_info *lc_inf = f->lc_inf;
02187   dbl_lr_info *lr_inf = f->lr_inf;
02188   double *lrcoef = 0;
02189   int *lrindx = 0;
02190   double *lccoef = f->lccoef;
02191   int *lcindx = f->lcindx;
02192   int nzcnt;
02193   int beg;
02194   int rnzcnt;
02195   int rbeg;
02196   int i;
02197   int j;
02198   int k;
02199   int c;
02200   int rval;
02201 
02202   nzcnt = 0;
02203   for (i = 0; i < dim; i++)
02204   {
02205     nzcnt += lc_inf[i].nzcnt;
02206     lr_inf[i].nzcnt = 0;
02207     lr_inf[i].delay = 0;
02208     lc_inf[lc_inf[i].c].crank = i;
02209   }
02210 
02211   dbl_EGlpNumFreeArray (f->lrcoef);
02212   if (nzcnt)
02213   {
02214     lrcoef = dbl_EGlpNumAllocArray (nzcnt);
02215     f->lrcoef = lrcoef;
02216   }
02217 
02218   ILL_IFFREE (f->lrindx, int);
02219   ILL_SAFE_MALLOC (lrindx, nzcnt + 1, int);
02220 
02221   f->lrindx = lrindx;
02222 
02223   for (i = 0; i < dim; i++)
02224   {
02225     nzcnt = lc_inf[i].nzcnt;
02226     beg = lc_inf[i].cbeg;
02227     lc_inf[i].delay = 0;
02228     for (j = 0; j < nzcnt; j++)
02229     {
02230       lr_inf[lc_inf[lcindx[beg + j]].crank].nzcnt++;
02231     }
02232   }
02233 
02234   nzcnt = 0;
02235   for (i = 0; i < dim; i++)
02236   {
02237     lr_inf[i].rbeg = nzcnt;
02238     nzcnt += lr_inf[i].nzcnt;
02239     lr_inf[i].nzcnt = 0;
02240     lr_inf[i].r = lc_inf[i].c;
02241     lr_inf[lr_inf[i].r].rrank = i;
02242   }
02243 
02244   for (i = 0; i < dim; i++)
02245   {
02246     nzcnt = lc_inf[i].nzcnt;
02247     beg = lc_inf[i].cbeg;
02248     c = lc_inf[i].c;
02249     for (j = 0; j < nzcnt; j++)
02250     {
02251       k = lc_inf[lcindx[beg + j]].crank;
02252       rbeg = lr_inf[k].rbeg;
02253       rnzcnt = lr_inf[k].nzcnt;
02254       lrindx[rbeg + rnzcnt] = c;
02255       dbl_EGlpNumCopy (lrcoef[rbeg + rnzcnt], lccoef[beg + j]);
02256       lr_inf[k].nzcnt++;
02257     }
02258   }
02259 
02260 #ifdef dbl_TRACK_FACTOR
02261   nzcnt = f->nzcnt_factor;
02262   for (i = 0; i < dim; i++)
02263   {
02264     nzcnt += lc_inf[i].nzcnt;
02265   }
02266   f->nzcnt_factor = nzcnt;
02267 
02268   dbl_EGlpNumCopy (f->maxelem_cur, f->maxelem_factor);
02269   f->nzcnt_cur = f->nzcnt_factor;
02270 
02271 /*
02272     dbl_dump_factor_stats (f);
02273     printf ("orig max  %e nzcnt %d\n", f->maxelem_orig, f->nzcnt_orig);
02274     printf ("f maxelem %e nzcnt %d\n", f->maxelem_cur, f->nzcnt_cur);
02275 */
02276 #endif /* dbl_TRACK_FACTOR */
02277 
02278   rval = 0;
02279 
02280 CLEANUP:
02281   EG_RETURN (rval);
02282 }
02283 
02284 static int dbl_handle_singularity (
02285   dbl_factor_work * f)
02286 {
02287   int rval = 0;
02288   int nsing;
02289   int *singr = 0;
02290   int *singc = 0;
02291   int i;
02292 
02293   if (f->p_nsing == 0 || f->p_singr == 0 || f->p_singc == 0)
02294   {
02295     fprintf (stderr, "singular basis, but no place for singularity data\n");
02296     return E_SING_NO_DATA;
02297   }
02298 
02299   nsing = f->nstages - f->stage;
02300   ILL_SAFE_MALLOC (singr, nsing, int);
02301   ILL_SAFE_MALLOC (singc, nsing, int);
02302 
02303   for (i = f->stage; i < f->nstages; i++)
02304   {
02305     singr[i - f->stage] = f->rperm[i];
02306     singc[i - f->stage] = f->cperm[i];
02307   }
02308   *f->p_nsing = nsing;
02309   *f->p_singr = singr;
02310   *f->p_singc = singc;
02311   singr = 0;
02312   singc = 0;
02313 
02314 CLEANUP:
02315   ILL_IFFREE (singr, int);
02316   ILL_IFFREE (singc, int);
02317 
02318   EG_RETURN (rval);
02319 }
02320 
02321 static int dbl_dense_build_matrix (
02322   dbl_factor_work * f)
02323 {
02324   double *dmat = 0;
02325   int stage = f->stage;
02326   int drows = f->nstages - stage;
02327   int dcols = f->dim - stage;
02328   int dsize = drows * dcols;
02329   int *crank = f->crank;
02330   double *urcoef = f->urcoef;
02331   int *urindx = f->urindx;
02332   int nzcnt;
02333   int beg;
02334   int i;
02335   int r;
02336   int j;
02337   int rval = 0;
02338 
02339   dmat = dbl_EGlpNumAllocArray (dsize);
02340 
02341   for (i = 0; i < dsize; i++)
02342     dbl_EGlpNumZero (dmat[i]);
02343 
02344   for (i = 0; i < drows; i++)
02345   {
02346     r = f->rperm[i + stage];
02347     nzcnt = f->ur_inf[r].nzcnt;
02348     beg = f->ur_inf[r].rbeg;
02349     for (j = 0; j < nzcnt; j++)
02350     {
02351       dbl_EGlpNumCopy (dmat[i * dcols - stage + crank[urindx[beg + j]]],
02352                    urcoef[beg + j]);
02353     }
02354   }
02355 
02356   f->drows = drows;
02357   f->dcols = dcols;
02358   f->dense_base = f->stage;
02359   f->dmat = dmat;
02360   dmat = 0;
02361 
02362 //CLEANUP:
02363   dbl_EGlpNumFreeArray (dmat);
02364   EG_RETURN (rval);
02365 }
02366 
02367 static int dbl_dense_find_pivot (
02368   dbl_factor_work * f,
02369   int *p_r,
02370   int *p_c)
02371 {
02372   int dcols = f->dcols;
02373   int drows = f->drows;
02374   double *dmat = f->dmat;
02375   int dense_base = f->dense_base;
02376   int s = f->stage - dense_base;
02377   dbl_ur_info *ur_inf = f->ur_inf;
02378   int *rperm = f->rperm;
02379   double maxval;
02380   int max_r;
02381   int max_c;
02382   int i;
02383 
02384   dbl_EGlpNumInitVar (maxval);
02385   dbl_EGlpNumZero (maxval);
02386   max_r = -1;
02387   for (i = s; i < drows; i++)
02388   {
02389     if (dbl_EGlpNumIsLess (maxval, ur_inf[rperm[dense_base + i]].max))
02390     {
02391       dbl_EGlpNumCopy (maxval, ur_inf[rperm[dense_base + i]].max);
02392       max_r = i;
02393     }
02394   }
02395   if (max_r == -1)
02396   {
02397     return E_NO_PIVOT;
02398   }
02399 
02400   dbl_EGlpNumZero (maxval);
02401   max_c = -1;
02402   for (i = s; i < drows; i++)
02403   {
02404     dbl_EGlpNumSetToMaxAbsAndDo (maxval, dmat[max_r * dcols + i], max_c = i);
02405   }
02406   if (max_c == -1)
02407   {
02408     return E_NO_PIVOT;
02409   }
02410   *p_r = max_r;
02411   *p_c = max_c;
02412 
02413   dbl_EGlpNumClearVar (maxval);
02414   return 0;
02415 }
02416 
02417 static void dbl_dense_swap (
02418   dbl_factor_work * f,
02419   int r,
02420   int c)
02421 {
02422   int dcols = f->dcols;
02423   int drows = f->drows;
02424   double *dmat = f->dmat;
02425   int dense_base = f->dense_base;
02426   int s = f->stage - dense_base;
02427   int i;
02428   double v;
02429 
02430   dbl_EGlpNumInitVar (v);
02431 
02432   if (r != s)
02433   {
02434     dbl_ILL_SWAP (f->rperm[dense_base + s], f->rperm[dense_base + r], i);
02435     f->rrank[f->rperm[dense_base + s]] = dense_base + s;
02436     f->rrank[f->rperm[dense_base + r]] = dense_base + r;
02437     for (i = 0; i < dcols; i++)
02438     {
02439       dbl_EGLPNUM_SWAP (dmat[s * dcols + i], dmat[r * dcols + i], v);
02440     }
02441   }
02442   if (c != s)
02443   {
02444     dbl_ILL_SWAP (f->cperm[dense_base + s], f->cperm[dense_base + c], i);
02445     f->crank[f->cperm[dense_base + s]] = dense_base + s;
02446     f->crank[f->cperm[dense_base + c]] = dense_base + c;
02447     for (i = 0; i < drows; i++)
02448     {
02449       dbl_EGLPNUM_SWAP (dmat[i * dcols + s], dmat[i * dcols + c], v);
02450     }
02451   }
02452   dbl_EGlpNumClearVar (v);
02453 }
02454 
02455 static void dbl_dense_elim (
02456   dbl_factor_work * f,
02457   int r,
02458   int c)
02459 {
02460   int dcols = f->dcols;
02461   int drows = f->drows;
02462   double *dmat = f->dmat;
02463   int dense_base = f->dense_base;
02464   int s = f->stage - dense_base;
02465   dbl_ur_info *ur_inf = f->ur_inf;
02466   int *rperm = f->rperm;
02467   int i;
02468   int j;
02469   double pivval;
02470   double max;
02471   double v;
02472   double w;
02473 
02474 #ifdef dbl_TRACK_FACTOR
02475   double maxelem_factor;
02476 
02477   dbl_EGlpNumInitVar (maxelem_factor);
02478   dbl_EGlpNumCopy (maxelem_factor, f->maxelem_factor);
02479 #endif
02480   dbl_EGlpNumInitVar (pivval);
02481   dbl_EGlpNumInitVar (max);
02482   dbl_EGlpNumInitVar (v);
02483   dbl_EGlpNumInitVar (w);
02484 
02485   dbl_dense_swap (f, r, c);
02486   f->stage++;
02487   dbl_EGlpNumCopyFrac (pivval, dbl_oneLpNum, dmat[s * dcols + s]);
02488   for (i = s + 1; i < drows; i++)
02489   {
02490     dbl_EGlpNumCopy (v, dmat[i * dcols + s]);
02491     if (dbl_EGlpNumIsNeqqZero (v))
02492     {
02493       dbl_EGlpNumMultTo (v, pivval);
02494       if (dbl_EGlpNumIsNeqZero (v, f->fzero_tol))
02495       {
02496         dbl_EGlpNumCopy (dmat[i * dcols + s], v);
02497 #ifdef dbl_TRACK_FACTOR
02498         dbl_EGlpNumSetToMaxAbs (maxelem_factor, v);
02499 #endif
02500         dbl_EGlpNumZero (max);
02501         for (j = s + 1; j < drows; j++)
02502         {
02503           dbl_EGlpNumCopy (w, dmat[i * dcols + j]);
02504           dbl_EGlpNumSubInnProdTo (w, v, dmat[s * dcols + j]);
02505           dbl_EGlpNumCopy (dmat[i * dcols + j], w);
02506           dbl_EGlpNumSetToMaxAbs (max, w);
02507         }
02508         for (j = drows; j < dcols; j++)
02509         {
02510           dbl_EGlpNumCopy (w, dmat[i * dcols + j]);
02511           dbl_EGlpNumSubInnProdTo (w, v, dmat[s * dcols + j]);
02512           dbl_EGlpNumCopy (dmat[i * dcols + j], w);
02513         }
02514         dbl_EGlpNumCopy (ur_inf[rperm[dense_base + i]].max, max);
02515 #ifdef dbl_TRACK_FACTOR
02516         if (dbl_EGlpNumIsLess (maxelem_factor, max))
02517           dbl_EGlpNumCopy (maxelem_factor, max);
02518 #endif
02519       }
02520       else
02521       {
02522         dbl_EGlpNumZero (dmat[i * dcols + s]);
02523       }
02524     }
02525   }
02526 #ifdef dbl_TRACK_FACTOR
02527   dbl_EGlpNumCopy (f->maxelem_factor, maxelem_factor);
02528   dbl_EGlpNumClearVar (maxelem_factor);
02529 #endif
02530   dbl_EGlpNumClearVar (pivval);
02531   dbl_EGlpNumClearVar (max);
02532   dbl_EGlpNumClearVar (v);
02533   dbl_EGlpNumClearVar (w);
02534 }
02535 
02536 static int dbl_dense_replace_row (
02537   dbl_factor_work * f,
02538   int i)
02539 {
02540   int dcols = f->dcols;
02541   int dense_base = f->dense_base;
02542   double *dmat = f->dmat + i * dcols;
02543   double *urcoef;
02544   dbl_ur_info *ur_inf = f->ur_inf;
02545   int *cperm = f->cperm;
02546   int r = f->rperm[dense_base + i];
02547   int *urindx;
02548   int nzcnt;
02549   int beg;
02550   int j;
02551   int rval = 0;
02552 
02553   nzcnt = 0;
02554   for (j = i; j < dcols; j++)
02555   {
02556     if (dbl_EGlpNumIsNeqZero (dmat[j], f->fzero_tol))
02557     {
02558       nzcnt++;
02559     }
02560   }
02561   if (nzcnt > ur_inf[r].nzcnt)
02562   {
02563     if (ur_inf[r].rbeg + ur_inf[r].nzcnt == f->ur_freebeg)
02564     {
02565       f->ur_freebeg = ur_inf[r].rbeg;
02566     }
02567     ur_inf[r].nzcnt = 0;
02568     if (f->ur_freebeg + nzcnt > f->ur_space)
02569     {
02570       rval = dbl_make_ur_space (f, nzcnt);
02571       CHECKRVALG (rval, CLEANUP);
02572     }
02573     ur_inf[r].rbeg = f->ur_freebeg;
02574     f->ur_freebeg += nzcnt;
02575   }
02576   beg = ur_inf[r].rbeg;
02577   urcoef = f->urcoef;
02578   urindx = f->urindx;
02579   for (j = i; j < dcols; j++)
02580   {
02581     if (dbl_EGlpNumIsNeqZero (dmat[j], f->fzero_tol))
02582     {
02583       dbl_EGlpNumCopy (urcoef[beg], dmat[j]);
02584       urindx[beg] = cperm[dense_base + j];
02585       beg++;
02586     }
02587   }
02588   ur_inf[r].nzcnt = beg - ur_inf[r].rbeg;
02589 CLEANUP:
02590   EG_RETURN (rval);
02591 }
02592 
02593 static int dbl_dense_create_col (
02594   dbl_factor_work * f,
02595   int i)
02596 {
02597   int dcols = f->dcols;
02598   int drows = f->drows;
02599   int dense_base = f->dense_base;
02600   double *dmat = f->dmat;
02601   double *lccoef;
02602   dbl_lc_info *lc_inf = f->lc_inf;
02603   int *rperm = f->rperm;
02604   int *lcindx;
02605   int nzcnt;
02606   int beg;
02607   int j;
02608   int rval = 0;
02609 
02610   nzcnt = 0;
02611   for (j = i + 1; j < drows; j++)
02612   {
02613     if (dbl_EGlpNumIsNeqZero (dmat[j * dcols + i], f->fzero_tol))
02614     {
02615       nzcnt++;
02616     }
02617   }
02618 
02619   if (f->lc_freebeg + nzcnt >= f->lc_space)
02620   {
02621     rval = dbl_make_lc_space (f, nzcnt);
02622     CHECKRVALG (rval, CLEANUP);
02623   }
02624   beg = f->lc_freebeg;
02625   lc_inf[dense_base + i].cbeg = beg;
02626   lc_inf[dense_base + i].c = rperm[dense_base + i];
02627   lcindx = f->lcindx;
02628   lccoef = f->lccoef;
02629 
02630   for (j = i + 1; j < drows; j++)
02631   {
02632     if (dbl_EGlpNumIsNeqZero (dmat[j * dcols + i], f->fzero_tol))
02633     {
02634       dbl_EGlpNumCopy (lccoef[beg], dmat[j * dcols + i]);
02635       lcindx[beg] = rperm[dense_base + j];
02636       beg++;
02637     }
02638   }
02639   lc_inf[dense_base + i].nzcnt = beg - lc_inf[dense_base + i].cbeg;
02640   f->lc_freebeg = beg;
02641 CLEANUP:
02642   EG_RETURN (rval);
02643 }
02644 
02645 static int dbl_dense_replace (
02646   dbl_factor_work * f)
02647 {
02648   int drows = f->drows;
02649   int rval = 0;
02650   int i;
02651 
02652   for (i = 0; i < drows; i++)
02653   {
02654     rval = dbl_dense_replace_row (f, i);
02655     CHECKRVALG (rval, CLEANUP);
02656     rval = dbl_dense_create_col (f, i);
02657     CHECKRVALG (rval, CLEANUP);
02658   }
02659   dbl_EGlpNumFreeArray (f->dmat);
02660   f->drows = 0;
02661   f->dcols = 0;
02662 CLEANUP:
02663   EG_RETURN (rval);
02664 }
02665 
02666 static int dbl_dense_factor (
02667   dbl_factor_work * f)
02668 {
02669   int r;
02670   int c;
02671   int rval = 0;
02672 
02673 #ifdef dbl_TRACK_FACTOR
02674 #ifdef dbl_NOTICE_BLOWUP
02675   double tmpsize;
02676 #endif
02677 #endif
02678 
02679 /*
02680     printf ("dense kernel, %d rows, %d  cols...\n", f->nstages - f->stage,
02681             f->dim - f->stage);
02682     fflush (stdout);
02683 */
02684 
02685   rval = dbl_dense_build_matrix (f);
02686   CHECKRVALG (rval, CLEANUP);
02687 
02688 #ifdef dbl_FACTOR_DEBUG
02689 #if (dbl_FACTOR_DEBUG+0>1)
02690   MESSAGE (0,"before Dense dbl_ILLfactor");
02691   dbl_dump_matrix (f, 1);
02692 #endif
02693 #endif
02694 
02695   while (f->stage < f->nstages)
02696   {
02697     r = f->stage - f->dense_base;
02698     rval = dbl_dense_find_pivot (f, &r, &c);
02699     if (rval == E_NO_PIVOT)
02700     {
02701       rval = dbl_handle_singularity (f);
02702       CHECKRVALG (rval, CLEANUP);
02703       return E_SINGULAR_INTERNAL;
02704     }
02705     else
02706     {
02707       CHECKRVALG (rval, CLEANUP);
02708     }
02709 #ifdef dbl_FACTOR_DEBUG
02710 #if (dbl_FACTOR_DEBUG+0>2)
02711     MESSAGE (0,"dense pivot elem: %d %d", r, c);
02712 #endif
02713 #endif /* dbl_FACTOR_DEBUG */
02714     dbl_dense_elim (f, r, c);
02715 
02716 #ifdef dbl_TRACK_FACTOR
02717 #ifdef dbl_NOTICE_BLOWUP
02718     tmpsize = f->maxmult * dbl_EGlpNumToLf (f->maxelem_orig);
02719     if (tmpsize < dbl_EGlpNumToLf (f->maxelem_factor) &&
02720         dbl_EGlpNumIsLess (f->partial_cur, dbl_oneLpNum))
02721     {
02722       return E_FACTOR_BLOWUP;
02723     }
02724 #endif /* dbl_NOTICE_BLOWUP */
02725 #endif /* dbl_TRACK_FACTOR */
02726 
02727 #ifdef dbl_FACTOR_DEBUG
02728 #if (dbl_FACTOR_DEBUG+0>1)
02729     MESSAGE (0,"After dense pivot stage %d (%d) of %d (%d)",
02730             f->stage - f->dense_base, f->stage,
02731             f->nstages - f->dense_base, f->nstages);
02732 #endif
02733 #if (dbl_FACTOR_DEBUG+0>2)
02734     dbl_dump_matrix (f, 1);
02735 #endif
02736 #endif /* dbl_FACTOR_DEBUG */
02737   }
02738 
02739 #ifdef dbl_FACTOR_DEBUG
02740   MESSAGE (0,"After dense dbl_ILLfactor:\n");
02741   dbl_dump_matrix (f, 0);
02742 #endif /* dbl_FACTOR_DEBUG */
02743 
02744   rval = dbl_dense_replace (f);
02745   CHECKRVALG (rval, CLEANUP);
02746 
02747 #ifdef dbl_FACTOR_DEBUG
02748   MESSAGE (0,"After replacement:\n");
02749   dbl_dump_matrix (f, 0);
02750 #endif /* dbl_FACTOR_DEBUG */
02751 
02752 CLEANUP:
02753   EG_RETURN (rval);
02754 }
02755 
02756 #ifdef dbl_RECORD
02757 FILE *dbl_fsave = 0;
02758 int dbl_fsavecnt = 0;
02759 #endif /* dbl_RECORD */
02760 
02761 static int dbl_ILLfactor_try (
02762   dbl_factor_work * f,
02763   int *basis,
02764   int *cbeg,
02765   int *clen,
02766   int *cindx,
02767   double * ccoef)
02768 {
02769   int rval = 0;
02770   int r;
02771   int c;
02772 
02773 #ifdef dbl_TRACK_FACTOR
02774 #ifdef dbl_NOTICE_BLOWUP
02775   double tmpsize;
02776 
02777   dbl_EGlpNumInitVar (tmpsize);
02778 #endif
02779 #endif
02780 
02781 #ifdef dbl_RECORD
02782   {
02783     int ncol = 0;
02784     int nzcnt = 0;
02785     int dim = f->dim;
02786     int i;
02787     int j;
02788     char fnambuf[40];
02789 
02790     for (i = 0; i < dim; i++)
02791     {
02792       if (basis[i] > ncol)
02793         ncol = basis[i];
02794     }
02795     ncol++;
02796     for (i = 0; i < ncol; i++)
02797     {
02798       nzcnt += clen[i];
02799     }
02800     if (dbl_fsave)
02801       fclose (dbl_fsave);
02802     sprintf (fnambuf, "prob.mat.%d", dbl_fsavecnt);
02803     dbl_fsavecnt++;
02804     dbl_fsave = fopen (fnambuf, "w");
02805     fprintf (dbl_fsave, "%d %d %d\n", f->dim, ncol, nzcnt);
02806     for (i = 0; i < dim; i++)
02807     {
02808       fprintf (dbl_fsave, "%d ", basis[i]);
02809     }
02810     fprintf (dbl_fsave, "\n");
02811     for (i = 0; i < ncol; i++)
02812     {
02813       fprintf (dbl_fsave, "%d", clen[i]);
02814       for (j = 0; j < clen[i]; j++)
02815       {
02816         fprintf (dbl_fsave, " %d %.16lg", cindx[cbeg[i] + j],
02817                  dbl_EGlpNumToLf (ccoef[cbeg[i] + j]));
02818       }
02819       fprintf (dbl_fsave, "\n");
02820     }
02821     fprintf (dbl_fsave, "\n");
02822     fflush (dbl_fsave);
02823   }
02824 #endif /* dbl_RECORD */
02825 
02826   rval = dbl_init_matrix (f, basis, cbeg, clen, cindx, ccoef);
02827   CHECKRVALG (rval, CLEANUP);
02828 
02829   f->stage = 0;
02830   f->nstages = f->dim;
02831 
02832 #ifdef dbl_FACTOR_DEBUG
02833   MESSAGE (0,"Initial matrix:");
02834 #if (dbl_FACTOR_DEBUG+0>1)
02835   dbl_dump_matrix (f, 0);
02836 #endif
02837 #endif /* dbl_FACTOR_DEBUG */
02838 #ifdef dbl_FACTOR_STATS
02839   printf ("Initial matrix: ");
02840   dbl_dump_factor_stats (f);
02841 #endif /* dbl_FACTOR_STATS */
02842 
02843   while (f->stage < f->nstages)
02844   {
02845     rval = dbl_find_pivot (f, &r, &c);
02846     if (rval == E_NO_PIVOT)
02847     {
02848       rval = dbl_handle_singularity (f);
02849       CHECKRVALG (rval, CLEANUP);
02850       return 0;
02851     }
02852     else
02853     {
02854       CHECKRVALG (rval, CLEANUP);
02855     }
02856     if (f->ur_inf[r].pivcnt > f->dense_fract * (f->nstages - f->stage) &&
02857         f->uc_inf[c].nzcnt > f->dense_fract * (f->nstages - f->stage) &&
02858         f->nstages - f->stage > f->dense_min)
02859     {
02860       rval = dbl_dense_factor (f);
02861       if (rval == E_SINGULAR_INTERNAL)
02862         return 0;
02863       if (rval)
02864         return rval;
02865       break;
02866     }
02867 #ifdef dbl_FACTOR_DEBUG
02868     MESSAGE (0,"pivot elem: %d %d", r, c);
02869 #endif /* dbl_FACTOR_DEBUG */
02870     rval = dbl_elim (f, r, c);
02871     CHECKRVALG (rval, CLEANUP);
02872 
02873 #ifdef dbl_TRACK_FACTOR
02874 #ifdef dbl_NOTICE_BLOWUP
02875     dbl_EGlpNumSet (tmpsize, f->maxmult);
02876     dbl_EGlpNumMultTo (tmpsize, f->maxelem_orig);
02877     if (dbl_EGlpNumIsLess (tmpsize, f->maxelem_factor) &&
02878         dbl_EGlpNumIsLess (f->partial_cur, dbl_oneLpNum))
02879     {
02880       return E_FACTOR_BLOWUP;
02881     }
02882 #endif /* dbl_NOTICE_BLOWUP */
02883 #endif /* dbl_TRACK_FACTOR */
02884 
02885 #ifdef dbl_FACTOR_DEBUG
02886 #if (dbl_FACTOR_DEBUG+0>3)
02887     MESSAGE (0,"After pivot stage %d of %d", f->stage, f->nstages);
02888     dbl_dump_matrix (f, 0);
02889 #endif
02890 #endif /* dbl_FACTOR_DEBUG */
02891   }
02892 
02893   rval = dbl_build_iteration_u_data (f);
02894   CHECKRVALG (rval, CLEANUP);
02895 
02896   rval = dbl_build_iteration_l_data (f);
02897   CHECKRVALG (rval, CLEANUP);
02898 
02899 #ifdef dbl_TRACK_FACTOR
02900 #ifdef dbl_NOTICE_BLOWUP
02901   dbl_EGlpNumSet (tmpsize, f->minmult);
02902   dbl_EGlpNumMultTo (tmpsize, f->maxelem_orig);
02903   if (dbl_EGlpNumIsLess (f->maxelem_factor, tmpsize) &&
02904       dbl_EGlpNumIsLess (f->partial_tol, f->partial_cur))
02905   {
02906     if (dbl_EGlpNumIsGreaDbl (f->partial_cur, 0.5))
02907     {
02908       dbl_EGlpNumSet (f->partial_cur, 0.5);
02909     }
02910     else if (dbl_EGlpNumIsGreaDbl (f->partial_cur, 0.25))
02911     {
02912       dbl_EGlpNumSet (f->partial_cur, 0.25);
02913     }
02914     else if (dbl_EGlpNumIsGreaDbl (f->partial_cur, 0.1))
02915     {
02916       dbl_EGlpNumSet (f->partial_cur, 0.1);
02917     }
02918     else
02919     {
02920       dbl_EGlpNumDivUiTo (f->partial_cur, 10);
02921     }
02922     if (dbl_EGlpNumIsLess (f->partial_cur, f->partial_tol))
02923     {
02924       dbl_EGlpNumCopy (f->partial_cur, f->partial_tol);
02925     }
02926 /*  Bico - comment out for dist 
02927         fprintf (stderr, "factor good, lowering partial tolerance to %.2f\n",
02928                  f->partial_cur);
02929 */
02930   }
02931 #endif /* dbl_NOTICE_BLOWUP */
02932 #endif /* dbl_TRACK_FACTOR */
02933 
02934 #ifdef dbl_FACTOR_DEBUG
02935   MESSAGE(0,"Factored matrix:");
02936 #if (dbl_FACTOR_DEBUG+0>1)
02937   dbl_dump_matrix (f, 0);
02938 #endif
02939 #endif /* dbl_FACTOR_DEBUG */
02940 
02941 #ifdef dbl_FACTOR_STATS
02942   printf ("Factored matrix: ");
02943   dbl_dump_factor_stats (f);
02944 #endif /* dbl_FACTOR_STATS */
02945 CLEANUP:
02946 #ifdef dbl_TRACK_FACTOR
02947 #ifdef dbl_NOTICE_BLOWUP
02948   dbl_EGlpNumClearVar (tmpsize);
02949 #endif
02950 #endif
02951   EG_RETURN (rval);
02952 }
02953 
02954 int dbl_ILLfactor (
02955   dbl_factor_work * f,
02956   int *basis,
02957   int *cbeg,
02958   int *clen,
02959   int *cindx,
02960   double * ccoef,
02961   int *p_nsing,
02962   int **p_singr,
02963   int **p_singc)
02964 {
02965   int rval;
02966 
02967   f->p_nsing = p_nsing;
02968   f->p_singr = p_singr;
02969   f->p_singc = p_singc;
02970   *p_nsing = 0;
02971 
02972 AGAIN:
02973   rval = dbl_ILLfactor_try (f, basis, cbeg, clen, cindx, ccoef);
02974   if (rval == E_FACTOR_BLOWUP)
02975   {
02976     if (dbl_EGlpNumIsLessDbl (f->partial_cur, 0.1))
02977     {
02978       dbl_EGlpNumMultUiTo (f->partial_cur, 10);
02979     }
02980     else if (dbl_EGlpNumIsLessDbl (f->partial_cur, 0.25))
02981     {
02982       dbl_EGlpNumSet (f->partial_cur, 0.25);
02983     }
02984     else if (dbl_EGlpNumIsLessDbl (f->partial_cur, 0.5))
02985     {
02986       dbl_EGlpNumSet (f->partial_cur, 0.5);
02987     }
02988     else if (dbl_EGlpNumIsLess (f->partial_cur, dbl_oneLpNum))
02989     {
02990       dbl_EGlpNumOne (f->partial_cur);
02991     }
02992     else
02993     {
02994       EG_RETURN (rval);
02995     }
02996 /* Bico - comment out for dist
02997         fprintf (stderr, "factor blowup, changing partial tolerance to %.2f\n",
02998                  f->partial_cur);
02999 */
03000     goto AGAIN;
03001   }
03002   EG_RETURN (rval);
03003 }
03004 
03005 static void dbl_ILLfactor_ftranl (
03006   dbl_factor_work * f,
03007   double * a)
03008 {
03009   int *lcindx = f->lcindx;
03010   dbl_lc_info *lc_inf = f->lc_inf;
03011   double *lccoef = f->lccoef;
03012   int dim = f->dim;
03013   int beg;
03014   int nzcnt;
03015   int i;
03016   int j;
03017   double v;
03018 
03019   dbl_EGlpNumInitVar (v);
03020 
03021   for (i = 0; i < dim; i++)
03022   {
03023     dbl_EGlpNumCopy (v, a[lc_inf[i].c]);
03024     if (dbl_EGlpNumIsNeqqZero (v))
03025     {
03026       nzcnt = lc_inf[i].nzcnt;
03027       beg = lc_inf[i].cbeg;
03028       for (j = 0; j < nzcnt; j++)
03029       {
03030         dbl_EGlpNumSubInnProdTo (a[lcindx[beg + j]], v, lccoef[beg + j]);
03031       }
03032     }
03033 #ifdef dbl_SOLVE_DEBUG
03034 #if (dbl_SOLVE_DEBUG+0 > 1)
03035     fpritf (stderr,"dbl_ILLfactor_ftran a after l %d:", i);
03036     for (j = 0; j < f->dim; j++)
03037     {
03038       fprintf (stderr," %.3f", dbl_EGlpNumToLf (a[j]));
03039     }
03040     MESSAGE(0," ");
03041 #endif
03042 #endif /* dbl_SOLVE_DEBUG */
03043   }
03044 #ifdef dbl_SOLVE_DEBUG
03045 #if (dbl_SOLVE_DEBUG+0 <= 1)
03046   printf ("dbl_ILLfactor_ftran a after l:");
03047   for (j = 0; j < f->dim; j++)
03048   {
03049     printf (" %.3f", dbl_EGlpNumToLf (a[j]));
03050   }
03051   printf ("\n");
03052   fflush (stdout);
03053 #endif
03054 #endif /* dbl_SOLVE_DEBUG */
03055   dbl_EGlpNumClearVar (v);
03056 }
03057 
03058 #if 0
03059 static void ftranl3_delay (
03060   dbl_factor_work * f,
03061   int c)
03062 {
03063   dbl_lc_info *lc_inf = f->lc_inf;
03064   int nzcnt;
03065   int *indx;
03066   int i;
03067 
03068   c = lc_inf[c].crank;
03069   nzcnt = lc_inf[c].nzcnt;
03070   indx = f->lcindx + lc_inf[c].cbeg;
03071   for (i = 0; i < nzcnt; i++)
03072   {
03073     c = indx[i];
03074     if (lc_inf[c].delay++ == 0)
03075     {
03076       ftranl3_delay (f, c);
03077     }
03078   }
03079 }
03080 #endif
03081 
03082 static void dbl_ftranl3_delay2 (
03083   dbl_factor_work * f,
03084   int c)
03085 {
03086   dbl_lc_info *lc_inf = f->lc_inf;
03087   int nzcnt;
03088   int *indx;
03089   int i;
03090   int last;
03091 
03092   do
03093   {
03094     c = lc_inf[c].crank;
03095     nzcnt = lc_inf[c].nzcnt;
03096     indx = f->lcindx + lc_inf[c].cbeg;
03097     last = -1;
03098     for (i = 0; i < nzcnt; i++)
03099     {
03100       c = indx[i];
03101       if (lc_inf[c].delay++ == 0)
03102       {
03103         if (last >= 0)
03104         {
03105           dbl_ftranl3_delay2 (f, last);
03106         }
03107         last = c;
03108       }
03109     }
03110     c = last;
03111   } while (c >= 0);
03112 }
03113 
03114 #if 0
03115 static void ftranl3_process (
03116   dbl_factor_work * f,
03117   int c,
03118   dbl_svector * x)
03119 {
03120   dbl_lc_info *lc_inf = f->lc_inf;
03121   double *work = f->work_coef;
03122   int nzcnt;
03123   int *indx;
03124   int i;
03125   double *coef;
03126   double v;
03127 
03128   dbl_EGlpNumInitVar (v);
03129 
03130   dbl_EGlpNumCopy (v, work[c]);
03131   dbl_EGlpNumZero (work[c]);
03132   if (dbl_EGlpNumIsNeqqZero (v))
03133   {
03134     x->indx[x->nzcnt] = c;
03135     dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
03136     x->nzcnt++;
03137   }
03138   c = lc_inf[c].crank;
03139   nzcnt = lc_inf[c].nzcnt;
03140   indx = f->lcindx + lc_inf[c].cbeg;
03141   coef = f->lccoef + lc_inf[c].cbeg;
03142   for (i = 0; i < nzcnt; i++)
03143   {
03144     c = indx[i];
03145     dbl_EGlpNumSubInnProdTo (work[c], v, coef[i]);
03146     if (--lc_inf[c].delay == 0)
03147     {
03148       ftranl3_process (f, c, x);
03149     }
03150   }
03151   dbl_EGlpNumClearVar (v);
03152 }
03153 #endif
03154 
03155 static void dbl_ftranl3_process2 (
03156   dbl_factor_work * f,
03157   int c,
03158   dbl_svector * x)
03159 {
03160   dbl_lc_info *lc_inf = f->lc_inf;
03161   double *work = f->work_coef;
03162   int nzcnt;
03163   int *indx;
03164   double *coef;
03165   int i;
03166   int last;
03167   double v;
03168 
03169   dbl_EGlpNumInitVar (v);
03170 
03171   do
03172   {
03173     dbl_EGlpNumCopy (v, work[c]);
03174     dbl_EGlpNumZero (work[c]);
03175     if (dbl_EGlpNumIsNeqqZero (v))
03176     {
03177       x->indx[x->nzcnt] = c;
03178       dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
03179       x->nzcnt++;
03180     }
03181     c = lc_inf[c].crank;
03182     nzcnt = lc_inf[c].nzcnt;
03183     indx = f->lcindx + lc_inf[c].cbeg;
03184     coef = f->lccoef + lc_inf[c].cbeg;
03185     last = -1;
03186     for (i = 0; i < nzcnt; i++)
03187     {
03188       c = indx[i];
03189       dbl_EGlpNumSubInnProdTo (work[c], v, coef[i]);
03190       if (--lc_inf[c].delay == 0)
03191       {
03192         if (last >= 0)
03193         {
03194           dbl_ftranl3_process2 (f, last, x);
03195         }
03196         last = c;
03197       }
03198     }
03199     c = last;
03200   } while (c >= 0);
03201   dbl_EGlpNumClearVar (v);
03202 }
03203 
03204 static void dbl_ILLfactor_ftranl3 (
03205   dbl_factor_work * f,
03206   dbl_svector * a,
03207   dbl_svector * x)
03208 {
03209   double *work = f->work_coef;
03210   int anzcnt = a->nzcnt;
03211   int *aindx = a->indx;
03212   double *acoef = a->coef;
03213   dbl_lc_info *lc_inf = f->lc_inf;
03214   int i;
03215 
03216   for (i = 0; i < anzcnt; i++)
03217   {
03218     if (lc_inf[aindx[i]].delay++ == 0)
03219     {
03220       dbl_ftranl3_delay2 (f, aindx[i]);
03221     }
03222     dbl_EGlpNumCopy (work[aindx[i]], acoef[i]);
03223   }
03224   x->nzcnt = 0;
03225   for (i = 0; i < anzcnt; i++)
03226   {
03227     if (--lc_inf[aindx[i]].delay == 0)
03228     {
03229       dbl_ftranl3_process2 (f, aindx[i], x);
03230     }
03231   }
03232 #ifdef dbl_SOLVE_DEBUG
03233   printf ("dbl_ILLfactor_ftran x after l3:");
03234   for (i = 0; i < x->nzcnt; i++)
03235   {
03236     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[i]), x->indx[i]);
03237   }
03238   printf ("\n");
03239   fflush (stdout);
03240 #endif /* dbl_SOLVE_DEBUG */
03241 }
03242 
03243 static void dbl_ILLfactor_ftrane (
03244   dbl_factor_work * f,
03245   double * a)
03246 {
03247   int *erindx = f->erindx;
03248   double *ercoef = f->ercoef;
03249   dbl_er_info *er_inf = f->er_inf;
03250   int etacnt = f->etacnt;
03251   int beg;
03252   int nzcnt;
03253   int i;
03254   int j;
03255   double v;
03256 
03257   dbl_EGlpNumInitVar (v);
03258 
03259   for (i = 0; i < etacnt; i++)
03260   {
03261     dbl_EGlpNumCopy (v, a[er_inf[i].r]);
03262     nzcnt = er_inf[i].nzcnt;
03263     beg = er_inf[i].rbeg;
03264     for (j = 0; j < nzcnt; j++)
03265     {
03266       dbl_EGlpNumSubInnProdTo (v, ercoef[beg + j], a[erindx[beg + j]]);
03267     }
03268     dbl_EGlpNumCopy (a[er_inf[i].r], v);
03269 #ifdef dbl_SOLVE_DEBUG
03270 #if (dbl_SOLVE_DEBUG+0 > 1)
03271     printf ("dbl_ILLfactor_ftran a after eta %d:", i);
03272     for (j = 0; j < f->dim; j++)
03273     {
03274       printf (" %.3f", dbl_EGlpNumToLf (a[j]));
03275     }
03276     printf ("\n");
03277     fflush (stdout);
03278 #endif
03279 #endif /* dbl_SOLVE_DEBUG */
03280   }
03281 #ifdef dbl_SOLVE_DEBUG
03282 #if (dbl_SOLVE_DEBUG+0 <= 1)
03283   printf ("dbl_ILLfactor_ftran a after eta:");
03284   for (j = 0; j < f->dim; j++)
03285   {
03286     printf (" %.3f", dbl_EGlpNumToLf (a[j]));
03287   }
03288   printf ("\n");
03289   fflush (stdout);
03290 #endif
03291 #endif /* dbl_SOLVE_DEBUG */
03292   dbl_EGlpNumClearVar (v);
03293 }
03294 
03295 static void dbl_ILLfactor_ftrane2 (
03296   dbl_factor_work * f,
03297   dbl_svector * a)
03298 {
03299   int *erindx = f->erindx;
03300   double *ercoef = f->ercoef;
03301   dbl_er_info *er_inf = f->er_inf;
03302   int etacnt = f->etacnt;
03303   int beg;
03304   int nzcnt;
03305   int anzcnt = a->nzcnt;
03306   int *aindx = a->indx;
03307   double *acoef = a->coef;
03308   double *work_coef = f->work_coef;
03309   int *work_indx = f->work_indx;
03310   int i;
03311   int j;
03312   int r;
03313   double v;
03314 
03315   dbl_EGlpNumInitVar (v);
03316 
03317   for (i = 0; i < anzcnt; i++)
03318   {
03319     dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03320     work_indx[aindx[i]] = i + 1;
03321   }
03322   for (i = 0; i < etacnt; i++)
03323   {
03324     r = er_inf[i].r;
03325     dbl_EGlpNumCopy (v, work_coef[r]);
03326     nzcnt = er_inf[i].nzcnt;
03327     beg = er_inf[i].rbeg;
03328     for (j = 0; j < nzcnt; j++)
03329     {
03330       dbl_EGlpNumSubInnProdTo (v, ercoef[beg + j], work_coef[erindx[beg + j]]);
03331     }
03332     if (dbl_EGlpNumIsNeqqZero (v))
03333     {
03334       dbl_EGlpNumCopy (work_coef[r], v);
03335       if (work_indx[r] == 0)
03336       {
03337         dbl_EGlpNumCopy (acoef[anzcnt], v);
03338         aindx[anzcnt] = r;
03339         work_indx[r] = anzcnt + 1;
03340         anzcnt++;
03341       }
03342       else
03343       {
03344         dbl_EGlpNumCopy (acoef[work_indx[r] - 1], v);
03345       }
03346     }
03347     else
03348     {
03349       dbl_EGlpNumZero (work_coef[r]);
03350       if (work_indx[r])
03351       {
03352         dbl_EGlpNumZero (acoef[work_indx[r] - 1]);
03353       }
03354     }
03355 #ifdef dbl_SOLVE_DEBUG
03356 #if (dbl_SOLVE_DEBUG+0 > 1)
03357     printf ("dbl_ILLfactor_ftran a after eta2 %d:", i);
03358     for (j = 0; j < anzcnt; j++)
03359     {
03360       printf (" %.3f*%d", dbl_EGlpNumToLf (acoef[j]), aindx[j]);
03361     }
03362     printf ("\n");
03363     fflush (stdout);
03364 #endif
03365 #endif /* dbl_SOLVE_DEBUG */
03366   }
03367   i = 0;
03368   while (i < anzcnt)
03369   {
03370     dbl_EGlpNumZero (work_coef[aindx[i]]);
03371     work_indx[aindx[i]] = 0;
03372     if (dbl_EGlpNumIsNeqZero (acoef[i], f->fzero_tol))
03373     {
03374       /*if (acoef[i] > fzero_tol || acoef[i] < -fzero_tol) */
03375       i++;
03376     }
03377     else
03378     {
03379       --anzcnt;
03380       dbl_EGlpNumCopy (acoef[i], acoef[anzcnt]);
03381       aindx[i] = aindx[anzcnt];
03382     }
03383   }
03384   a->nzcnt = anzcnt;
03385 
03386 #ifdef dbl_SOLVE_DEBUG
03387 #if (dbl_SOLVE_DEBUG+0 <= 1)
03388   printf ("dbl_ILLfactor_ftran a after eta2:");
03389   for (j = 0; j < anzcnt; j++)
03390   {
03391     printf (" %.3f*%d", dbl_EGlpNumToLf (acoef[j]), aindx[j]);
03392   }
03393   printf ("\n");
03394   fflush (stdout);
03395 #endif
03396 #endif /* dbl_SOLVE_DEBUG */
03397   dbl_EGlpNumClearVar (v);
03398 }
03399 
03400 static void dbl_ILLfactor_ftranu (
03401   dbl_factor_work * f,
03402   double * a,
03403   dbl_svector * x)
03404 {
03405   int *ucindx = f->ucindx;
03406   double *uccoef = f->uccoef;
03407   dbl_uc_info *uc_inf = f->uc_inf;
03408   int *cperm = f->cperm;
03409   int *rperm = f->rperm;
03410   int dim = f->dim;
03411   int xnzcnt = 0;
03412   int *xindx = x->indx;
03413   double *xcoef = x->coef;
03414   int nzcnt;
03415   int beg;
03416   int i;
03417   int j;
03418   double v;
03419 
03420   dbl_EGlpNumInitVar (v);
03421 
03422   for (i = dim - 1; i >= 0; i--)
03423   {
03424     dbl_EGlpNumCopy (v, a[rperm[i]]);
03425     if (dbl_EGlpNumIsNeqqZero (v))  /*((v = a[rperm[i]]) != 0.0) */
03426     {
03427       j = cperm[i];
03428       beg = uc_inf[j].cbeg;
03429       dbl_EGlpNumDivTo (v, uccoef[beg]);
03430       if (dbl_EGlpNumIsNeqZero (v, f->szero_tol))
03431       {
03432         /*if (v > szero_tol || v < -szero_tol) */
03433         xindx[xnzcnt] = j;
03434         dbl_EGlpNumCopy (xcoef[xnzcnt], v);
03435         xnzcnt++;
03436       }
03437       nzcnt = uc_inf[j].nzcnt;
03438       for (j = 1; j < nzcnt; j++)
03439       {
03440         dbl_EGlpNumSubInnProdTo (a[ucindx[beg + j]], v, uccoef[beg + j]);
03441       }
03442       dbl_EGlpNumZero (a[rperm[i]]);
03443     }
03444   }
03445   x->nzcnt = xnzcnt;
03446 #ifdef dbl_SOLVE_DEBUG
03447   printf ("dbl_ILLfactor_ftran x after u:");
03448   for (j = 0; j < x->nzcnt; j++)
03449   {
03450     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[j]), x->indx[j]);
03451   }
03452   printf ("\n");
03453   fflush (stdout);
03454 #endif /* dbl_SOLVE_DEBUG */
03455   dbl_EGlpNumClearVar (v);
03456 }
03457 
03458 
03459 #if 0
03460 static void ftranu3_delay (
03461   dbl_factor_work * f,
03462   int c)
03463 {
03464   dbl_uc_info *uc_inf = f->uc_inf;
03465   int nzcnt;
03466   int *indx;
03467   int i;
03468 
03469   c = f->cperm[f->rrank[c]];
03470   nzcnt = uc_inf[c].nzcnt;
03471   indx = f->ucindx + uc_inf[c].cbeg;
03472   for (i = 1; i < nzcnt; i++)
03473   {
03474     c = indx[i];
03475     if (uc_inf[c].delay++ == 0)
03476     {
03477       ftranu3_delay (f, c);
03478     }
03479   }
03480 }
03481 #endif
03482 
03483 static void dbl_ftranu3_delay2 (
03484   dbl_factor_work * f,
03485   int c)
03486 {
03487   dbl_uc_info *uc_inf = f->uc_inf;
03488   int nzcnt;
03489   int *indx;
03490   int i;
03491   int last;
03492 
03493   do
03494   {
03495     c = f->cperm[f->rrank[c]];
03496     nzcnt = uc_inf[c].nzcnt;
03497     indx = f->ucindx + uc_inf[c].cbeg;
03498     last = -1;
03499     for (i = 1; i < nzcnt; i++)
03500     {
03501       c = indx[i];
03502       if (uc_inf[c].delay++ == 0)
03503       {
03504         if (last >= 0)
03505         {
03506           dbl_ftranu3_delay2 (f, last);
03507         }
03508         last = c;
03509       }
03510     }
03511     c = last;
03512   } while (c >= 0);
03513 }
03514 
03515 #if 0
03516 static void ftranu3_process (
03517   dbl_factor_work * f,
03518   int c,
03519   dbl_svector * x)
03520 {
03521   dbl_uc_info *uc_inf = f->uc_inf;
03522   double *work = f->work_coef;
03523   int nzcnt;
03524   int *indx;
03525   double *coef;
03526   int i;
03527   double v;
03528 
03529   dbl_EGlpNumInitVar (v);
03530 
03531   dbl_EGlpNumCopy (v, work[c]);
03532   dbl_EGlpNumZero (work[c]);
03533   c = f->cperm[f->rrank[c]];
03534   nzcnt = uc_inf[c].nzcnt;
03535   indx = f->ucindx + uc_inf[c].cbeg;
03536   coef = f->uccoef + uc_inf[c].cbeg;
03537   dbl_EGlpNumDivTo (v, coef[0]);
03538   if (dbl_EGlpNumIsNeqZero (v, f->szero_tol))
03539     /*if (v > szero_tol || v < -szero_tol) */
03540   {
03541     x->indx[x->nzcnt] = c;
03542     dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
03543     x->nzcnt++;
03544   }
03545   for (i = 1; i < nzcnt; i++)
03546   {
03547     c = indx[i];
03548     dbl_EGlpNumSubInnProdTo (work[c], v, coef[i]);
03549     if (--uc_inf[c].delay == 0)
03550     {
03551       ftranu3_process (f, c, x);
03552     }
03553   }
03554   dbl_EGlpNumClearVar (v);
03555 }
03556 #endif
03557 
03558 static void dbl_ftranu3_process2 (
03559   dbl_factor_work * f,
03560   int c,
03561   dbl_svector * x)
03562 {
03563   dbl_uc_info *uc_inf = f->uc_inf;
03564   double *work = f->work_coef;
03565   int nzcnt;
03566   int *indx;
03567   double *coef;
03568   int i;
03569   int last;
03570   double v;
03571 
03572   dbl_EGlpNumInitVar (v);
03573 
03574   do
03575   {
03576     dbl_EGlpNumCopy (v, work[c]);
03577     dbl_EGlpNumZero (work[c]);
03578     c = f->cperm[f->rrank[c]];
03579     nzcnt = uc_inf[c].nzcnt;
03580     indx = f->ucindx + uc_inf[c].cbeg;
03581     coef = f->uccoef + uc_inf[c].cbeg;
03582     dbl_EGlpNumDivTo (v, coef[0]);
03583     if (dbl_EGlpNumIsNeqZero (v, f->szero_tol))
03584       /*if (v > szero_tol || v < -szero_tol) */
03585     {
03586       x->indx[x->nzcnt] = c;
03587       dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
03588       x->nzcnt++;
03589     }
03590     last = -1;
03591     for (i = 1; i < nzcnt; i++)
03592     {
03593       c = indx[i];
03594       dbl_EGlpNumSubInnProdTo (work[c], v, coef[i]);
03595       if (--uc_inf[c].delay == 0)
03596       {
03597         if (last >= 0)
03598         {
03599           dbl_ftranu3_process2 (f, last, x);
03600         }
03601         last = c;
03602       }
03603     }
03604     c = last;
03605   } while (c >= 0);
03606   dbl_EGlpNumClearVar (v);
03607 }
03608 
03609 static void dbl_ILLfactor_ftranu3 (
03610   dbl_factor_work * f,
03611   dbl_svector * a,
03612   dbl_svector * x)
03613 {
03614   double *work = f->work_coef;
03615   int anzcnt = a->nzcnt;
03616   int *aindx = a->indx;
03617   double *acoef = a->coef;
03618   dbl_uc_info *uc_inf = f->uc_inf;
03619   int i;
03620 
03621   for (i = 0; i < anzcnt; i++)
03622   {
03623     if (uc_inf[aindx[i]].delay++ == 0)
03624     {
03625       dbl_ftranu3_delay2 (f, aindx[i]);
03626     }
03627     dbl_EGlpNumCopy (work[aindx[i]], acoef[i]);
03628   }
03629   x->nzcnt = 0;
03630   for (i = 0; i < anzcnt; i++)
03631   {
03632     if (--uc_inf[aindx[i]].delay == 0)
03633     {
03634       dbl_ftranu3_process2 (f, aindx[i], x);
03635     }
03636   }
03637 #ifdef dbl_SOLVE_DEBUG
03638   printf ("dbl_ILLfactor_ftran x after u3:");
03639   for (i = 0; i < x->nzcnt; i++)
03640   {
03641     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[i]), x->indx[i]);
03642   }
03643   printf ("\n");
03644   fflush (stdout);
03645 #endif /* dbl_SOLVE_DEBUG */
03646 }
03647 
03648 /* dbl_ILLfactor_ftran solves Bx=a for x */
03649 void dbl_ILLfactor_ftran (
03650   dbl_factor_work * f,
03651   dbl_svector * a,
03652   dbl_svector * x)
03653 {
03654   int i;
03655   int nzcnt;
03656   int sparse;
03657   int *aindx;
03658   double *acoef;
03659   double *work_coef = f->work_coef;
03660 
03661 #ifdef dbl_RECORD
03662   {
03663     fprintf (dbl_fsave, "f %d", a->nzcnt);
03664     for (i = 0; i < a->nzcnt; i++)
03665     {
03666       fprintf (dbl_fsave, " %d %.16e", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
03667     }
03668     fprintf (dbl_fsave, "\n");
03669     fflush (dbl_fsave);
03670   }
03671 #endif /* dbl_RECORD */
03672 #ifdef dbl_DEBUG_FACTOR
03673   {
03674     printf ("dbl_ILLfactor_ftran a:");
03675     for (i = 0; i < a->nzcnt; i++)
03676     {
03677       printf (" %d %la", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
03678     }
03679     printf ("\n");
03680     fflush (stdout);
03681   }
03682 #endif /* dbl_DEBUG_FACTOR */
03683 
03684   if (a->nzcnt >= SPARSE_FACTOR * f->dim)
03685   {
03686     nzcnt = a->nzcnt;
03687     aindx = a->indx;
03688     acoef = a->coef;
03689     for (i = 0; i < nzcnt; i++)
03690     {
03691       dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03692     }
03693     sparse = 0;
03694   }
03695   else
03696   {
03697     sparse = 1;
03698   }
03699 
03700   if (sparse)
03701   {
03702     dbl_ILLfactor_ftranl3 (f, a, &f->xtmp);
03703     if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim)
03704     {
03705       nzcnt = f->xtmp.nzcnt;
03706       aindx = f->xtmp.indx;
03707       acoef = f->xtmp.coef;
03708 
03709       for (i = 0; i < nzcnt; i++)
03710       {
03711         dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03712       }
03713       sparse = 0;
03714     }
03715   }
03716   else
03717   {
03718     dbl_ILLfactor_ftranl (f, work_coef);
03719   }
03720 
03721   if (sparse)
03722   {
03723     dbl_ILLfactor_ftrane2 (f, &f->xtmp);
03724     if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim)
03725     {
03726       nzcnt = f->xtmp.nzcnt;
03727       aindx = f->xtmp.indx;
03728       acoef = f->xtmp.coef;
03729 
03730       for (i = 0; i < nzcnt; i++)
03731       {
03732         dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03733       }
03734       sparse = 0;
03735     }
03736   }
03737   else
03738   {
03739     dbl_ILLfactor_ftrane (f, work_coef);
03740   }
03741 
03742   if (sparse)
03743   {
03744     dbl_ILLfactor_ftranu3 (f, &f->xtmp, x);
03745   }
03746   else
03747   {
03748     dbl_ILLfactor_ftranu (f, work_coef, x);
03749   }
03750 
03751 #ifdef dbl_SORT_RESULTS
03752   dbl_sort_vector (x);
03753 #endif
03754 
03755 #ifdef dbl_DEBUG_FACTOR
03756   {
03757     printf ("dbl_ILLfactor_ftran x:");
03758     for (i = 0; i < x->nzcnt; i++)
03759     {
03760       printf (" %d %la", x->indx[i], dbl_EGlpNumToLf (x->coef[i]));
03761     }
03762     printf ("\n");
03763     fflush (stdout);
03764   }
03765 #endif /* dbl_DEBUG_FACTOR */
03766   return;
03767 }
03768 
03769 /* dbl_ILLfactor_ftran_update solves Bx=a for x, and also returns upd, where Ux=upd */
03770 void dbl_ILLfactor_ftran_update (
03771   dbl_factor_work * f,
03772   dbl_svector * a,
03773   dbl_svector * upd,
03774   dbl_svector * x)
03775 {
03776   int i;
03777   int nzcnt;
03778   int dim;
03779   int sparse;
03780   int *aindx;
03781   double *acoef;
03782   double *work_coef = f->work_coef;
03783 
03784 #ifdef dbl_RECORD
03785   {
03786     fprintf (dbl_fsave, "F %d", a->nzcnt);
03787     for (i = 0; i < a->nzcnt; i++)
03788     {
03789       fprintf (dbl_fsave, " %d %.16e", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
03790     }
03791     fprintf (dbl_fsave, "\n");
03792     fflush (dbl_fsave);
03793   }
03794 #endif /* dbl_RECORD */
03795 #ifdef dbl_DEBUG_FACTOR
03796   {
03797     printf ("dbl_ILLfactor_ftran_update a:");
03798     for (i = 0; i < a->nzcnt; i++)
03799     {
03800       printf (" %d %.3f", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
03801     }
03802     printf ("\n");
03803     fflush (stdout);
03804   }
03805 #endif /* dbl_DEBUG_FACTOR */
03806 
03807   if (a->nzcnt >= SPARSE_FACTOR * f->dim)
03808   {
03809     aindx = a->indx;
03810     acoef = a->coef;
03811     nzcnt = a->nzcnt;
03812 
03813     for (i = 0; i < nzcnt; i++)
03814     {
03815       dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03816     }
03817     sparse = 0;
03818   }
03819   else
03820   {
03821     sparse = 1;
03822   }
03823 
03824   if (sparse)
03825   {
03826     dbl_ILLfactor_ftranl3 (f, a, upd);
03827     if (upd->nzcnt >= SPARSE_FACTOR * f->dim)
03828     {
03829       nzcnt = upd->nzcnt;
03830       aindx = upd->indx;
03831       acoef = upd->coef;
03832 
03833       for (i = 0; i < nzcnt; i++)
03834       {
03835         dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03836       }
03837       sparse = 0;
03838     }
03839   }
03840   else
03841   {
03842     dbl_ILLfactor_ftranl (f, work_coef);
03843   }
03844 
03845   if (sparse)
03846   {
03847     dbl_ILLfactor_ftrane2 (f, upd);
03848     if (upd->nzcnt >= SPARSE_FACTOR * f->dim)
03849     {
03850       nzcnt = upd->nzcnt;
03851       aindx = upd->indx;
03852       acoef = upd->coef;
03853 
03854       for (i = 0; i < nzcnt; i++)
03855       {
03856         dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
03857       }
03858       sparse = 0;
03859     }
03860   }
03861   else
03862   {
03863     dbl_ILLfactor_ftrane (f, work_coef);
03864     nzcnt = 0;
03865     dim = f->dim;
03866     aindx = upd->indx;
03867     acoef = upd->coef;
03868     for (i = 0; i < dim; i++)
03869     {
03870       if (dbl_EGlpNumIsNeqqZero (work_coef[i]))
03871       {
03872         if (dbl_EGlpNumIsNeqZero (work_coef[i], f->szero_tol))
03873           /*if(work_coef[i] > szero_tol || work_coef[i] < -szero_tol) */
03874         {
03875           aindx[nzcnt] = i;
03876           dbl_EGlpNumCopy (acoef[nzcnt], work_coef[i]);
03877           nzcnt++;
03878         }
03879       }
03880     }
03881     upd->nzcnt = nzcnt;
03882   }
03883 
03884   if (sparse)
03885   {
03886     dbl_ILLfactor_ftranu3 (f, upd, x);
03887   }
03888   else
03889   {
03890     dbl_ILLfactor_ftranu (f, work_coef, x);
03891   }
03892 
03893 #ifdef dbl_SORT_RESULTS
03894   dbl_sort_vector (upd);
03895   dbl_sort_vector (x);
03896 #endif
03897 
03898 #ifdef dbl_DEBUG_FACTOR
03899   {
03900     printf ("dbl_ILLfactor_ftran update x:");
03901     for (i = 0; i < x->nzcnt; i++)
03902     {
03903       printf (" %d %.3f", x->indx[i], dbl_EGlpNumToLf (x->coef[i]));
03904     }
03905     printf ("\n");
03906     fflush (stdout);
03907   }
03908 #endif /* dbl_DEBUG_FACTOR */
03909 }
03910 
03911 
03912 static void dbl_ILLfactor_btranl2 (
03913   dbl_factor_work * f,
03914   double * x)
03915 {
03916   int *lrindx = f->lrindx;
03917   double *lrcoef = f->lrcoef;
03918   dbl_lr_info *lr_inf = f->lr_inf;
03919   int dim = f->dim;
03920   int nzcnt;
03921   int beg;
03922   int i;
03923   int j;
03924   double v;
03925 
03926   dbl_EGlpNumInitVar (v);
03927 
03928   for (i = dim - 1; i >= 0; i--)
03929   {
03930 #ifdef dbl_SOLVE_DEBUG
03931 #if (dbl_SOLVE_DEBUG+0 > 1)
03932     printf ("dbl_ILLfactor_btran x before l2 %d:", i);
03933     for (j = 0; j < f->dim; j++)
03934     {
03935       printf (" %.3f", dbl_EGlpNumToLf (x[j]));
03936     }
03937     printf ("\n");
03938     fflush (stdout);
03939 #endif
03940 #endif /* dbl_SOLVE_DEBUG */
03941     dbl_EGlpNumCopy (v, x[lr_inf[i].r]);
03942     if (dbl_EGlpNumIsNeqqZero (v))
03943     {
03944       nzcnt = lr_inf[i].nzcnt;
03945       beg = lr_inf[i].rbeg;
03946       for (j = 0; j < nzcnt; j++)
03947       {
03948         dbl_EGlpNumSubInnProdTo (x[lrindx[beg + j]], v, lrcoef[beg + j]);
03949       }
03950     }
03951   }
03952 #ifdef dbl_SOLVE_DEBUG
03953 #if (dbl_SOLVE_DEBUG+0 <= 1)
03954   printf ("dbl_ILLfactor_btran x after l2:");
03955   for (j = 0; j < f->dim; j++)
03956   {
03957     printf (" %.3f", dbl_EGlpNumToLf (x[j]));
03958   }
03959   printf ("\n");
03960   fflush (stdout);
03961 #endif
03962 #endif /* dbl_SOLVE_DEBUG */
03963   dbl_EGlpNumClearVar (v);
03964 }
03965 
03966 #if 0
03967 static void btranl3_delay (
03968   dbl_factor_work * f,
03969   int r)
03970 {
03971   dbl_lr_info *lr_inf = f->lr_inf;
03972   int nzcnt;
03973   int *indx;
03974   int i;
03975 
03976   r = lr_inf[r].rrank;
03977   nzcnt = lr_inf[r].nzcnt;
03978   indx = f->lrindx + lr_inf[r].rbeg;
03979   for (i = 0; i < nzcnt; i++)
03980   {
03981     r = indx[i];
03982     if (lr_inf[r].delay++ == 0)
03983     {
03984       btranl3_delay (f, r);
03985     }
03986   }
03987 }
03988 #endif
03989 
03990 static void dbl_btranl3_delay2 (
03991   dbl_factor_work * f,
03992   int r)
03993 {
03994   dbl_lr_info *lr_inf = f->lr_inf;
03995   int nzcnt;
03996   int *indx;
03997   int i;
03998   int last;
03999 
04000   do
04001   {
04002     r = lr_inf[r].rrank;
04003     nzcnt = lr_inf[r].nzcnt;
04004     indx = f->lrindx + lr_inf[r].rbeg;
04005     last = -1;
04006     for (i = 0; i < nzcnt; i++)
04007     {
04008       r = indx[i];
04009       if (lr_inf[r].delay++ == 0)
04010       {
04011         if (last >= 0)
04012         {
04013           dbl_btranl3_delay2 (f, last);
04014         }
04015         last = r;
04016       }
04017     }
04018     r = last;
04019   } while (r >= 0);
04020 }
04021 
04022 #if 0
04023 static void btranl3_process (
04024   dbl_factor_work * f,
04025   int r,
04026   dbl_svector * x)
04027 {
04028   dbl_lr_info *lr_inf = f->lr_inf;
04029   double *work = f->work_coef;
04030   int nzcnt;
04031   int *indx;
04032   double *coef;
04033   int i;
04034   double v;
04035 
04036   dbl_EGlpNumInitVar (v);
04037 
04038   dbl_EGlpNumCopy (v, work[r]);
04039   dbl_EGlpNumZero (work[r]);
04040   if (dbl_EGlpNumIsNeqZero (v, f->szero_tol))
04041     /*if (v > szero_tol || v < -szero_tol) */
04042   {
04043     x->indx[x->nzcnt] = r;
04044     dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
04045     x->nzcnt++;
04046   }
04047   r = lr_inf[r].rrank;
04048   nzcnt = lr_inf[r].nzcnt;
04049   indx = f->lrindx + lr_inf[r].rbeg;
04050   coef = f->lrcoef + lr_inf[r].rbeg;
04051   for (i = 0; i < nzcnt; i++)
04052   {
04053     r = indx[i];
04054     dbl_EGlpNumSubInnProdTo (work[r], v, coef[i]);
04055     if (--lr_inf[r].delay == 0)
04056     {
04057       btranl3_process (f, r, x);
04058     }
04059   }
04060   dbl_EGlpNumClearVar (v);
04061 }
04062 #endif
04063 
04064 static void dbl_btranl3_process2 (
04065   dbl_factor_work * f,
04066   int r,
04067   dbl_svector * x)
04068 {
04069   dbl_lr_info *lr_inf = f->lr_inf;
04070   double *work = f->work_coef;
04071   int nzcnt;
04072   int *indx;
04073   double *coef;
04074   int i;
04075   int last;
04076   double v;
04077 
04078   dbl_EGlpNumInitVar (v);
04079 
04080   do
04081   {
04082     dbl_EGlpNumCopy (v, work[r]);
04083     dbl_EGlpNumZero (work[r]);
04084     if (dbl_EGlpNumIsNeqZero (v, f->szero_tol))
04085       /*if (v > szero_tol || v < -szero_tol) */
04086     {
04087       x->indx[x->nzcnt] = r;
04088       dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
04089       x->nzcnt++;
04090     }
04091     r = lr_inf[r].rrank;
04092     nzcnt = lr_inf[r].nzcnt;
04093     indx = f->lrindx + lr_inf[r].rbeg;
04094     coef = f->lrcoef + lr_inf[r].rbeg;
04095     last = -1;
04096     for (i = 0; i < nzcnt; i++)
04097     {
04098       r = indx[i];
04099       dbl_EGlpNumSubInnProdTo (work[r], v, coef[i]);
04100       if (--lr_inf[r].delay == 0)
04101       {
04102         if (last >= 0)
04103         {
04104           dbl_btranl3_process2 (f, last, x);
04105         }
04106         last = r;
04107       }
04108     }
04109     r = last;
04110   } while (r >= 0);
04111   dbl_EGlpNumClearVar (v);
04112 }
04113 
04114 static void dbl_ILLfactor_btranl3 (
04115   dbl_factor_work * f,
04116   dbl_svector * a,
04117   dbl_svector * x)
04118 {
04119   double *work = f->work_coef;
04120   int anzcnt = a->nzcnt;
04121   int *aindx = a->indx;
04122   double *acoef = a->coef;
04123   dbl_lr_info *lr_inf = f->lr_inf;
04124   int i;
04125 
04126   for (i = 0; i < anzcnt; i++)
04127   {
04128     if (lr_inf[aindx[i]].delay++ == 0)
04129     {
04130       dbl_btranl3_delay2 (f, aindx[i]);
04131     }
04132     dbl_EGlpNumCopy (work[aindx[i]], acoef[i]);
04133   }
04134   x->nzcnt = 0;
04135   for (i = 0; i < anzcnt; i++)
04136   {
04137     if (--lr_inf[aindx[i]].delay == 0)
04138     {
04139       dbl_btranl3_process2 (f, aindx[i], x);
04140     }
04141   }
04142 #ifdef dbl_SOLVE_DEBUG
04143   printf ("dbl_ILLfactor_btran x after l3:");
04144   for (i = 0; i < x->nzcnt; i++)
04145   {
04146     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[i]), x->indx[i]);
04147   }
04148   printf ("\n");
04149   fflush (stdout);
04150 #endif /* dbl_SOLVE_DEBUG */
04151 }
04152 
04153 static void dbl_ILLfactor_btrane (
04154   dbl_factor_work * f,
04155   double * x)
04156 {
04157   int *erindx = f->erindx;
04158   double *ercoef = f->ercoef;
04159   dbl_er_info *er_inf = f->er_inf;
04160   int etacnt = f->etacnt;
04161   int beg;
04162   int nzcnt;
04163   int i;
04164   int j;
04165   double v;
04166 
04167   dbl_EGlpNumInitVar (v);
04168 
04169   for (i = etacnt - 1; i >= 0; i--)
04170   {
04171 #ifdef dbl_SOLVE_DEBUG
04172 #if (dbl_SOLVE_DEBUG+0 > 1)
04173     printf ("dbl_ILLfactor_btran x before eta %d:", i);
04174     for (j = 0; j < f->dim; j++)
04175     {
04176       printf (" %.3f", dbl_EGlpNumToLf (x[j]));
04177     }
04178     printf ("\n");
04179     fflush (stdout);
04180 #endif
04181 #endif /* dbl_SOLVE_DEBUG */
04182     dbl_EGlpNumCopy (v, x[er_inf[i].r]);
04183     if (dbl_EGlpNumIsNeqqZero (v))
04184     {
04185       nzcnt = er_inf[i].nzcnt;
04186       beg = er_inf[i].rbeg;
04187       for (j = 0; j < nzcnt; j++)
04188       {
04189         dbl_EGlpNumSubInnProdTo (x[erindx[beg + j]], v, ercoef[beg + j]);
04190       }
04191     }
04192   }
04193 #ifdef dbl_SOLVE_DEBUG
04194 #if (dbl_SOLVE_DEBUG+0 <= 1)
04195   printf ("dbl_ILLfactor_btran x after eta:");
04196   for (j = 0; j < f->dim; j++)
04197   {
04198     printf (" %.3f", dbl_EGlpNumToLf (x[j]));
04199   }
04200   printf ("\n");
04201   fflush (stdout);
04202 #endif
04203 #endif /* dbl_SOLVE_DEBUG */
04204   dbl_EGlpNumClearVar (v);
04205 }
04206 
04207 static void dbl_ILLfactor_btrane2 (
04208   dbl_factor_work * f,
04209   dbl_svector * x)
04210 {
04211   int *erindx = f->erindx;
04212   double *ercoef = f->ercoef;
04213   dbl_er_info *er_inf = f->er_inf;
04214   int etacnt = f->etacnt;
04215   int beg;
04216   int nzcnt;
04217   int xnzcnt = x->nzcnt;
04218   int *xindx = x->indx;
04219   double *xcoef = x->coef;
04220   double *work_coef = f->work_coef;
04221   int *work_indx = f->work_indx;
04222   int i;
04223   int j;
04224   double v;
04225 
04226   dbl_EGlpNumInitVar (v);
04227 
04228   for (i = 0; i < xnzcnt; i++)
04229   {
04230     dbl_EGlpNumCopy (work_coef[xindx[i]], xcoef[i]);
04231     work_indx[xindx[i]] = i + 1;
04232   }
04233   for (i = etacnt - 1; i >= 0; i--)
04234   {
04235 #ifdef dbl_SOLVE_DEBUG
04236 #if (dbl_SOLVE_DEBUG+0 > 1)
04237     printf ("dbl_ILLfactor_btran x before eta2 %d:", i);
04238     for (j = 0; j < xnzcnt; j++)
04239     {
04240       printf (" %.3f*%d", dbl_EGlpNumToLf (work_coef[xindx[j]]), xindx[j]);
04241     }
04242     printf ("\n");
04243     fflush (stdout);
04244 #endif
04245 #endif /* dbl_SOLVE_DEBUG */
04246     dbl_EGlpNumCopy (v, work_coef[er_inf[i].r]);
04247     if (dbl_EGlpNumIsNeqqZero (v))
04248     {
04249       nzcnt = er_inf[i].nzcnt;
04250       beg = er_inf[i].rbeg;
04251       for (j = 0; j < nzcnt; j++)
04252       {
04253         if (work_indx[erindx[beg + j]] == 0)
04254         {
04255           work_indx[erindx[beg + j]] = xnzcnt;
04256           xindx[xnzcnt++] = erindx[beg + j];
04257         }
04258         dbl_EGlpNumSubInnProdTo (work_coef[erindx[beg + j]], v, ercoef[beg + j]);
04259       }
04260     }
04261   }
04262 
04263   j = 0;
04264   while (j < xnzcnt)
04265   {
04266     dbl_EGlpNumCopy (xcoef[j], work_coef[xindx[j]]);
04267     dbl_EGlpNumZero (work_coef[xindx[j]]);
04268     work_indx[xindx[j]] = 0;
04269     if (!dbl_EGlpNumIsNeqqZero (xcoef[j]))
04270     {
04271       --xnzcnt;
04272       xindx[j] = xindx[xnzcnt];
04273     }
04274     else
04275     {
04276       j++;
04277     }
04278   }
04279   x->nzcnt = xnzcnt;
04280 
04281 #ifdef dbl_SOLVE_DEBUG
04282 #if (dbl_SOLVE_DEBUG+0 <= 1)
04283   printf ("dbl_ILLfactor_btran x after eta2:");
04284   for (j = 0; j < xnzcnt; j++)
04285   {
04286     printf (" %.3f*%d", dbl_EGlpNumToLf (xcoef[j]), xindx[j]);
04287   }
04288   printf ("\n");
04289   fflush (stdout);
04290 #endif
04291 #endif /* dbl_SOLVE_DEBUG */
04292   dbl_EGlpNumClearVar (v);
04293 }
04294 
04295 static void dbl_ILLfactor_btranu (
04296   dbl_factor_work * f,
04297   double * a,
04298   dbl_svector * x)
04299 {
04300   int *urindx = f->urindx;
04301   double *urcoef = f->urcoef;
04302   dbl_ur_info *ur_inf = f->ur_inf;
04303   int *rperm = f->rperm;
04304   int *cperm = f->cperm;
04305   int dim = f->dim;
04306   int xnzcnt = 0;
04307   int *xindx = x->indx;
04308   double *xcoef = x->coef;
04309   int nzcnt;
04310   int beg;
04311   int i;
04312   int j;
04313   double v;
04314 
04315   dbl_EGlpNumInitVar (v);
04316 
04317   for (i = 0; i < dim; i++)
04318   {
04319     dbl_EGlpNumCopy (v, a[cperm[i]]);
04320     if (dbl_EGlpNumIsNeqqZero (v))
04321     {
04322       j = rperm[i];
04323       beg = ur_inf[j].rbeg;
04324       dbl_EGlpNumDivTo (v, urcoef[beg]);
04325       if (dbl_EGlpNumIsNeqZero (v, f->szero_tol)) /*
04326                                                * if (v > szero_tol || v < -szero_tol) */
04327       {
04328         xindx[xnzcnt] = j;
04329         dbl_EGlpNumCopy (xcoef[xnzcnt], v);
04330         xnzcnt++;
04331       }
04332       nzcnt = ur_inf[j].nzcnt;
04333       for (j = 1; j < nzcnt; j++)
04334       {
04335         dbl_EGlpNumSubInnProdTo (a[urindx[beg + j]], v, urcoef[beg + j]);
04336       }
04337       dbl_EGlpNumZero (a[cperm[i]]);
04338     }
04339   }
04340   x->nzcnt = xnzcnt;
04341 #ifdef dbl_SOLVE_DEBUG
04342   printf ("dbl_ILLfactor_btran x after u:");
04343   for (i = 0; i < x->nzcnt; i++)
04344   {
04345     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[i]), x->indx[i]);
04346   }
04347   printf ("\n");
04348   fflush (stdout);
04349 #endif /* dbl_SOLVE_DEBUG */
04350   dbl_EGlpNumClearVar (v);
04351 }
04352 
04353 
04354 #if 0
04355 static void btranu3_delay (
04356   dbl_factor_work * f,
04357   int r)
04358 {
04359   dbl_ur_info *ur_inf = f->ur_inf;
04360   int nzcnt;
04361   int *indx;
04362   int i;
04363 
04364   r = f->rperm[f->crank[r]];
04365   nzcnt = ur_inf[r].nzcnt;
04366   indx = f->urindx + ur_inf[r].rbeg;
04367   for (i = 1; i < nzcnt; i++)
04368   {
04369     r = indx[i];
04370     if (ur_inf[r].delay++ == 0)
04371     {
04372       btranu3_delay (f, r);
04373     }
04374   }
04375 }
04376 #endif
04377 
04378 static void dbl_btranu3_delay2 (
04379   dbl_factor_work * f,
04380   int r)
04381 {
04382   dbl_ur_info *ur_inf = f->ur_inf;
04383   int nzcnt;
04384   int *indx;
04385   int i;
04386   int last;
04387 
04388   do
04389   {
04390     r = f->rperm[f->crank[r]];
04391     nzcnt = ur_inf[r].nzcnt;
04392     indx = f->urindx + ur_inf[r].rbeg;
04393     last = -1;
04394     for (i = 1; i < nzcnt; i++)
04395     {
04396       r = indx[i];
04397       if (ur_inf[r].delay++ == 0)
04398       {
04399         if (last >= 0)
04400         {
04401           dbl_btranu3_delay2 (f, last);
04402         }
04403         last = r;
04404       }
04405     }
04406     r = last;
04407   } while (r >= 0);
04408 }
04409 
04410 #if 0
04411 static void btranu3_process (
04412   dbl_factor_work * f,
04413   int r,
04414   dbl_svector * x)
04415 {
04416   dbl_ur_info *ur_inf = f->ur_inf;
04417   double *work = f->work_coef;
04418   int nzcnt;
04419   int *indx;
04420   double *coef;
04421   int i;
04422   double v;
04423 
04424   dbl_EGlpNumInitVar (v);
04425 
04426   dbl_EGlpNumCopy (v, work[r]);
04427   dbl_EGlpNumZero (work[r]);
04428   r = f->rperm[f->crank[r]];
04429   nzcnt = ur_inf[r].nzcnt;
04430   indx = f->urindx + ur_inf[r].rbeg;
04431   coef = f->urcoef + ur_inf[r].rbeg;
04432   dbl_EGlpNumDivTo (v, coef[0]);
04433   if (dbl_EGlpNumIsNeqqZero (v))
04434   {
04435     x->indx[x->nzcnt] = r;
04436     dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
04437     x->nzcnt++;
04438   }
04439   for (i = 1; i < nzcnt; i++)
04440   {
04441     r = indx[i];
04442     dbl_EGlpNumSubInnProdTo (work[r], v, coef[i]);
04443     if (--ur_inf[r].delay == 0)
04444     {
04445       btranu3_process (f, r, x);
04446     }
04447   }
04448   dbl_EGlpNumClearVar (v);
04449 }
04450 #endif
04451 
04452 static void dbl_btranu3_process2 (
04453   dbl_factor_work * f,
04454   int r,
04455   dbl_svector * x)
04456 {
04457   dbl_ur_info *ur_inf = f->ur_inf;
04458   double *work = f->work_coef;
04459   int nzcnt;
04460   int *indx;
04461   double *coef;
04462   int i;
04463   int last;
04464   double v;
04465 
04466   dbl_EGlpNumInitVar (v);
04467 
04468   do
04469   {
04470     dbl_EGlpNumCopy (v, work[r]);
04471     dbl_EGlpNumZero (work[r]);
04472     r = f->rperm[f->crank[r]];
04473     nzcnt = ur_inf[r].nzcnt;
04474     indx = f->urindx + ur_inf[r].rbeg;
04475     coef = f->urcoef + ur_inf[r].rbeg;
04476     dbl_EGlpNumDivTo (v, coef[0]);
04477     if (dbl_EGlpNumIsNeqqZero (v))
04478     {
04479       x->indx[x->nzcnt] = r;
04480       dbl_EGlpNumCopy (x->coef[x->nzcnt], v);
04481       x->nzcnt++;
04482     }
04483     last = -1;
04484     for (i = 1; i < nzcnt; i++)
04485     {
04486       r = indx[i];
04487       dbl_EGlpNumSubInnProdTo (work[r], v, coef[i]);
04488       if (--ur_inf[r].delay == 0)
04489       {
04490         if (last >= 0)
04491         {
04492           dbl_btranu3_process2 (f, last, x);
04493         }
04494         last = r;
04495       }
04496     }
04497     r = last;
04498   } while (r >= 0);
04499   dbl_EGlpNumClearVar (v);
04500 }
04501 
04502 static void dbl_ILLfactor_btranu3 (
04503   dbl_factor_work * f,
04504   dbl_svector * a,
04505   dbl_svector * x)
04506 {
04507   double *work = f->work_coef;
04508   int anzcnt = a->nzcnt;
04509   int *aindx = a->indx;
04510   double *acoef = a->coef;
04511   dbl_ur_info *ur_inf = f->ur_inf;
04512   int i;
04513 
04514   for (i = 0; i < anzcnt; i++)
04515   {
04516     if (ur_inf[aindx[i]].delay++ == 0)
04517     {
04518       dbl_btranu3_delay2 (f, aindx[i]);
04519     }
04520     dbl_EGlpNumCopy (work[aindx[i]], acoef[i]);
04521   }
04522   x->nzcnt = 0;
04523   for (i = 0; i < anzcnt; i++)
04524   {
04525     if (--ur_inf[aindx[i]].delay == 0)
04526     {
04527       dbl_btranu3_process2 (f, aindx[i], x);
04528     }
04529   }
04530 #ifdef dbl_SOLVE_DEBUG
04531   printf ("dbl_ILLfactor_btran x after u3:");
04532   for (i = 0; i < x->nzcnt; i++)
04533   {
04534     printf (" %.3f*%d", dbl_EGlpNumToLf (x->coef[i]), x->indx[i]);
04535   }
04536   printf ("\n");
04537   fflush (stdout);
04538 #endif /* dbl_SOLVE_DEBUG */
04539 }
04540 
04541 /* dbl_ILLfactor_btran solves x^tB=a^t (or, B^t x = a) for x */
04542 void dbl_ILLfactor_btran (
04543   dbl_factor_work * f,
04544   dbl_svector * a,
04545   dbl_svector * x)
04546 {
04547   int i;
04548   int nzcnt;
04549   int sparse;
04550   int *aindx = a->indx;
04551   double *acoef = a->coef;
04552   double *work_coef = f->work_coef;
04553   int dim = f->dim;
04554 
04555 #ifdef dbl_RECORD
04556   {
04557     fprintf (dbl_fsave, "b %d", a->nzcnt);
04558     for (i = 0; i < a->nzcnt; i++)
04559     {
04560       fprintf (dbl_fsave, " %d %.16e", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
04561     }
04562     fprintf (dbl_fsave, "\n");
04563     fflush (dbl_fsave);
04564   }
04565 #endif /* dbl_RECORD */
04566 #ifdef dbl_DEBUG_FACTOR
04567   {
04568     printf ("dbl_ILLfactor_btran a:");
04569     for (i = 0; i < a->nzcnt; i++)
04570     {
04571       printf (" %d %.3f", a->indx[i], dbl_EGlpNumToLf (a->coef[i]));
04572     }
04573     printf ("\n");
04574     fflush (stdout);
04575   }
04576 #endif /* dbl_DEBUG_FACTOR */
04577 
04578   if (a->nzcnt >= SPARSE_FACTOR * f->dim)
04579   {
04580     aindx = a->indx;
04581     acoef = a->coef;
04582     work_coef = f->work_coef;
04583     nzcnt = a->nzcnt;
04584     for (i = 0; i < nzcnt; i++)
04585     {
04586       dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
04587     }
04588     sparse = 0;
04589   }
04590   else
04591   {
04592     sparse = 1;
04593   }
04594 
04595   if (sparse)
04596   {
04597     dbl_ILLfactor_btranu3 (f, a, &f->xtmp);
04598   }
04599   else
04600   {
04601     dbl_ILLfactor_btranu (f, work_coef, &f->xtmp);
04602   }
04603 
04604   if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim)
04605   {
04606     aindx = f->xtmp.indx;
04607     acoef = f->xtmp.coef;
04608     work_coef = f->work_coef;
04609     nzcnt = f->xtmp.nzcnt;
04610     for (i = 0; i < nzcnt; i++)
04611     {
04612       dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
04613     }
04614     sparse = 0;
04615   }
04616   else
04617   {
04618     sparse = 1;
04619   }
04620 
04621   if (sparse)
04622   {
04623     dbl_ILLfactor_btrane2 (f, &f->xtmp);
04624     if (f->xtmp.nzcnt >= SPARSE_FACTOR * f->dim)
04625     {
04626       aindx = f->xtmp.indx;
04627       acoef = f->xtmp.coef;
04628       work_coef = f->work_coef;
04629       nzcnt = f->xtmp.nzcnt;
04630       for (i = 0; i < nzcnt; i++)
04631       {
04632         dbl_EGlpNumCopy (work_coef[aindx[i]], acoef[i]);
04633       }
04634       sparse = 0;
04635     }
04636   }
04637   else
04638   {
04639     dbl_ILLfactor_btrane (f, work_coef);
04640   }
04641 
04642   if (sparse)
04643   {
04644     dbl_ILLfactor_btranl3 (f, &f->xtmp, x);
04645   }
04646   else
04647   {
04648     dbl_ILLfactor_btranl2 (f, work_coef);
04649     dim = f->dim;
04650     nzcnt = 0;
04651     aindx = x->indx;
04652     acoef = x->coef;
04653     for (i = 0; i < dim; i++)
04654     {
04655       if (dbl_EGlpNumIsNeqqZero (work_coef[i]))
04656       {
04657         if (dbl_EGlpNumIsNeqZero (work_coef[i], f->szero_tol))
04658           /*if (work_coef[i] > szero_tol || work_coef[i] < -szero_tol) */
04659         {
04660           aindx[nzcnt] = i;
04661           dbl_EGlpNumCopy (acoef[nzcnt], work_coef[i]);
04662           nzcnt++;
04663         }
04664         dbl_EGlpNumZero (work_coef[i]);
04665       }
04666     }
04667     x->nzcnt = nzcnt;
04668   }
04669 
04670 #ifdef dbl_SORT_RESULTS
04671   dbl_sort_vector (x);
04672 #endif
04673 
04674 #ifdef dbl_DEBUG_FACTOR
04675   {
04676     printf ("dbl_ILLfactor_btran x:");
04677     for (i = 0; i < x->nzcnt; i++)
04678     {
04679       printf (" %d %.3f", x->indx[i], dbl_EGlpNumToLf (x->coef[i]));
04680     }
04681     printf ("\n");
04682     fflush (stdout);
04683   }
04684 #endif /* dbl_DEBUG_FACTOR */
04685   return;
04686 }
04687 
04688 static int dbl_expand_col (
04689   dbl_factor_work * f,
04690   int col)
04691 {
04692   dbl_uc_info *uc_inf = f->uc_inf + col;
04693   int uc_freebeg = f->uc_freebeg;
04694   int nzcnt = uc_inf->nzcnt;
04695   int cbeg;
04696   double *uccoef;
04697   int *ucindx;
04698   int *ucrind;
04699   int i;
04700   int rval = 0;
04701 
04702   if (uc_freebeg + nzcnt + 1 >= f->uc_space)
04703   {
04704     rval = dbl_make_uc_space (f, nzcnt + 1);
04705     CHECKRVALG (rval, CLEANUP);
04706     uc_freebeg = f->uc_freebeg;
04707   }
04708   cbeg = uc_inf->cbeg;
04709   uccoef = f->uccoef;
04710   ucindx = f->ucindx;
04711   ucrind = f->ucrind;
04712 
04713   for (i = 0; i < nzcnt; i++)
04714   {
04715     dbl_EGlpNumCopy (uccoef[uc_freebeg + i], uccoef[cbeg + i]);
04716     ucindx[uc_freebeg + i] = ucindx[cbeg + i];
04717     ucrind[uc_freebeg + i] = ucrind[cbeg + i];
04718     ucindx[cbeg + i] = -1;
04719   }
04720 
04721   uc_inf->cbeg = uc_freebeg;
04722   f->uc_freebeg = uc_freebeg + nzcnt;
04723 CLEANUP:
04724   EG_RETURN (rval);
04725 }
04726 
04727 static int dbl_expand_row (
04728   dbl_factor_work * f,
04729   int row)
04730 {
04731   dbl_ur_info *ur_inf = f->ur_inf + row;
04732   int ur_freebeg = f->ur_freebeg;
04733   int nzcnt = ur_inf->nzcnt;
04734   int rbeg;
04735   double *urcoef;
04736   int *urindx;
04737   int *urcind;
04738   int i;
04739   int rval = 0;
04740 
04741   if (ur_freebeg + nzcnt + 1 >= f->ur_space)
04742   {
04743     rval = dbl_make_ur_space (f, nzcnt + 1);
04744     CHECKRVALG (rval, CLEANUP);
04745     ur_freebeg = f->ur_freebeg;
04746   }
04747   rbeg = ur_inf->rbeg;
04748   urcoef = f->urcoef;
04749   urindx = f->urindx;
04750   urcind = f->urcind;
04751 
04752   for (i = 0; i < nzcnt; i++)
04753   {
04754     dbl_EGlpNumCopy (urcoef[ur_freebeg + i], urcoef[rbeg + i]);
04755     urindx[ur_freebeg + i] = urindx[rbeg + i];
04756     urcind[ur_freebeg + i] = urcind[rbeg + i];
04757     urindx[rbeg + i] = -1;
04758   }
04759 
04760   ur_inf->rbeg = ur_freebeg;
04761   f->ur_freebeg = ur_freebeg + nzcnt;
04762 CLEANUP:
04763   EG_RETURN (rval);
04764 }
04765 
04766 static int dbl_add_nonzero (
04767   dbl_factor_work * f,
04768   int row,
04769   int col,
04770   double val)
04771 {
04772   dbl_ur_info *ur_inf = f->ur_inf + row;
04773   dbl_uc_info *uc_inf = f->uc_inf + col;
04774   int cnzcnt = uc_inf->nzcnt;
04775   int rnzcnt = ur_inf->nzcnt;
04776   int cloc = uc_inf->cbeg + cnzcnt;
04777   int rloc = ur_inf->rbeg + rnzcnt;
04778   int rval = 0;
04779 
04780   if (f->ucindx[cloc] != -1)
04781   {
04782     rval = dbl_expand_col (f, col);
04783     CHECKRVALG (rval, CLEANUP);
04784     cloc = uc_inf->cbeg + cnzcnt;
04785   }
04786   TESTG ((rval = (rloc < 0 || rloc > f->ur_space)), CLEANUP,
04787          "rloc %d outside boundaries [0:%d]", rloc, f->ur_space);
04788   if (f->urindx[rloc] != -1)
04789   {
04790     rval = dbl_expand_row (f, row);
04791     CHECKRVALG (rval, CLEANUP);
04792     rloc = ur_inf->rbeg + rnzcnt;
04793   }
04794   f->ucindx[cloc] = row;
04795   dbl_EGlpNumCopy (f->uccoef[cloc], val);
04796   f->ucrind[cloc] = rnzcnt;
04797   f->urindx[rloc] = col;
04798   dbl_EGlpNumCopy (f->urcoef[rloc], val);
04799   f->urcind[rloc] = cnzcnt;
04800 
04801   if (cloc == f->uc_freebeg)
04802     f->uc_freebeg++;
04803   if (rloc == f->ur_freebeg)
04804     f->ur_freebeg++;
04805 
04806   uc_inf->nzcnt = cnzcnt + 1;
04807   ur_inf->nzcnt = rnzcnt + 1;
04808 CLEANUP:
04809   EG_RETURN (rval);
04810 }
04811 
04812 static int dbl_delete_nonzero_row (
04813   dbl_factor_work * f,
04814   int row,
04815   int ind)
04816 {
04817   dbl_ur_info *ur_inf = f->ur_inf;
04818   double *urcoef = f->urcoef;
04819   int *urindx = f->urindx;
04820   int *urcind = f->urcind;
04821   int *ucrind = f->ucrind;
04822   int rbeg = ur_inf[row].rbeg;
04823   int nzcnt = ur_inf[row].nzcnt - 1;
04824   int cbeg, rval = 0;
04825   #ifdef dbl_DEBUG_FACTOR
04826   TESTG((rval=(nzcnt<0)),CLEANUP,"Deleting empty row %d ind %d!",row, ind);
04827   #endif
04828 
04829   if (ind != nzcnt)
04830   {
04831     dbl_EGlpNumCopy (urcoef[rbeg + ind], urcoef[rbeg + nzcnt]);
04832     urindx[rbeg + ind] = urindx[rbeg + nzcnt];
04833     urcind[rbeg + ind] = urcind[rbeg + nzcnt];
04834     cbeg = f->uc_inf[urindx[rbeg + nzcnt]].cbeg;
04835     ucrind[cbeg + urcind[rbeg + nzcnt]] = ind;
04836     urindx[rbeg + nzcnt] = -1;
04837   }
04838   ur_inf[row].nzcnt = nzcnt;
04839   #ifdef dbl_DEBUG_FACTOR
04840   CLEANUP:
04841   #endif
04842   return rval;
04843 }
04844 
04845 static void dbl_delete_nonzero_col (
04846   dbl_factor_work * f,
04847   int col,
04848   int ind)
04849 {
04850   dbl_uc_info *uc_inf = f->uc_inf;
04851   double *uccoef = f->uccoef;
04852   int *ucindx = f->ucindx;
04853   int *ucrind = f->ucrind;
04854   int *urcind = f->urcind;
04855   int cbeg = uc_inf[col].cbeg;
04856   int nzcnt = uc_inf[col].nzcnt - 1;
04857   int rbeg;
04858 
04859   if (ind != nzcnt)
04860   {
04861     dbl_EGlpNumCopy (uccoef[cbeg + ind], uccoef[cbeg + nzcnt]);
04862     ucindx[cbeg + ind] = ucindx[cbeg + nzcnt];
04863     ucrind[cbeg + ind] = ucrind[cbeg + nzcnt];
04864     rbeg = f->ur_inf[ucindx[cbeg + nzcnt]].rbeg;
04865     urcind[rbeg + ucrind[cbeg + nzcnt]] = ind;
04866     ucindx[cbeg + nzcnt] = -1;
04867   }
04868   uc_inf[col].nzcnt = nzcnt;
04869 }
04870 
04871 static int dbl_delete_column (
04872   dbl_factor_work * f,
04873   int col)
04874 {
04875   dbl_uc_info *uc_inf = f->uc_inf;
04876   int beg = uc_inf[col].cbeg;
04877   int nzcnt = uc_inf[col].nzcnt;
04878   int *ucindx = f->ucindx + beg;
04879   int *ucrind = f->ucrind + beg;
04880   int i, rval = 0;
04881   #ifdef dbl_DEBUG_FACTOR
04882   rval = dbl_check_matrix(f);
04883   TESTG(rval,CLEANUP,"Corrupted Matrix");
04884   #endif
04885 
04886   for (i = 0; i < nzcnt; i++)
04887   {
04888     rval = dbl_delete_nonzero_row (f, ucindx[i], ucrind[i]);
04889     CHECKRVALG(rval,CLEANUP);
04890     ucindx[i] = -1;
04891   }
04892   uc_inf[col].nzcnt = 0;
04893 
04894 #ifdef dbl_TRACK_FACTOR
04895   f->nzcnt_cur -= nzcnt;
04896 #endif
04897 
04898   #ifdef dbl_DEBUG_FACTOR
04899   rval = dbl_check_matrix(f);
04900   TESTG(rval,CLEANUP,"Corrupted Matrix");
04901   #endif /* dbl_DEBUG_FACTOR */
04902   CLEANUP:
04903   EG_RETURN(rval);
04904 }
04905 
04906 static int dbl_delete_row (
04907   dbl_factor_work * f,
04908   int row,
04909   dbl_svector * x)
04910 {
04911   dbl_ur_info *ur_inf = f->ur_inf;
04912   int beg = ur_inf[row].rbeg;
04913   int nzcnt = ur_inf[row].nzcnt;
04914   int *urindx = f->urindx + beg;
04915   double *urcoef = f->urcoef + beg;
04916   int *urcind = f->urcind + beg;
04917   int i,rval=0;
04918 
04919   #ifdef dbl_DEBUG_FACTOR
04920   rval = dbl_check_matrix(f);
04921   TESTG(rval,CLEANUP,"Corrupted Matrix");
04922   #endif /* dbl_DEBUG_FACTOR */
04923 
04924   for (i = 0; i < nzcnt; i++)
04925   {
04926     x->indx[i] = urindx[i];
04927     dbl_EGlpNumCopy (x->coef[i], urcoef[i]);
04928     dbl_delete_nonzero_col (f, urindx[i], urcind[i]);
04929     urindx[i] = -1;
04930   }
04931   x->nzcnt = nzcnt;
04932   ur_inf[row].nzcnt = 0;
04933 
04934 #ifdef dbl_TRACK_FACTOR
04935   f->nzcnt_cur -= nzcnt;
04936 #endif
04937 
04938   #ifdef dbl_DEBUG_FACTOR
04939   rval = dbl_check_matrix(f);
04940   TESTG(rval,CLEANUP,"Corrupted Matrix");
04941   CLEANUP:
04942   #endif /* dbl_DEBUG_FACTOR */
04943   return rval;
04944 }
04945 
04946 static int dbl_create_column (
04947   dbl_factor_work * f,
04948   dbl_svector * a,
04949   int col,
04950   int *p_last_rank)
04951 {
04952   int *rrank = f->rrank;
04953   int nzcnt = a->nzcnt;
04954   int *aindx = a->indx;
04955   double *acoef = a->coef;
04956   int i;
04957   int j;
04958   int rval = 0;
04959   int last_rank = -1;
04960 
04961 #ifdef dbl_TRACK_FACTOR
04962   double max;
04963 
04964   dbl_EGlpNumInitVar (max);
04965   dbl_EGlpNumCopy (max, f->maxelem_cur);
04966 #endif /* dbl_TRACK_FACTOR */
04967 
04968   last_rank = 0;
04969 
04970   for (i = 0; i < nzcnt; i++)
04971   {
04972     rval = dbl_add_nonzero (f, aindx[i], col, acoef[i]);
04973     CHECKRVALG (rval, CLEANUP);
04974 #ifdef dbl_TRACK_FACTOR
04975     dbl_EGlpNumSetToMaxAbs (max, acoef[i]);
04976 #endif /* dbl_TRACK_FACTOR */
04977     j = rrank[aindx[i]];
04978     if (j > last_rank)
04979       last_rank = j;
04980   }
04981   *p_last_rank = last_rank;
04982 
04983 #ifdef dbl_TRACK_FACTOR
04984   f->nzcnt_cur += nzcnt;
04985   dbl_EGlpNumCopy (f->maxelem_cur, max);
04986   dbl_EGlpNumClearVar (max);
04987 #endif /* dbl_TRACK_FACTOR */
04988 
04989   #ifdef dbl_DEBUG_FACTOR
04990   rval = dbl_check_matrix(f);
04991   TESTG(rval,CLEANUP,"Corrupted Matrix");
04992   #endif /* dbl_DEBUG_FACTOR */
04993 
04994   CLEANUP:
04995   EG_RETURN (rval);
04996 }
04997 
04998 #ifdef dbl_UPDATE_STUDY
04999 static int dbl_column_rank (
05000   dbl_factor_work * f,
05001   int col)
05002 {
05003   int *cperm = f->cperm;
05004   int dim = f->dim;
05005   int i;
05006 
05007   for (i = 0; i < dim; i++)
05008   {
05009     if (cperm[i] == col)
05010     {
05011       return i;
05012     }
05013   }
05014   return 0;
05015 }
05016 #endif
05017 
05018 static void dbl_shift_permutations (
05019   dbl_factor_work * f,
05020   int rank_p,
05021   int rank_r)
05022 {
05023   int *cperm = f->cperm;
05024   int *crank = f->crank;
05025   int *rperm = f->rperm;
05026   int *rrank = f->rrank;
05027   int col_p = cperm[rank_p];
05028   int row_p = rperm[rank_p];
05029   int i;
05030 
05031   for (i = rank_p; i < rank_r; i++)
05032   {
05033     cperm[i] = cperm[i + 1];
05034     crank[cperm[i]] = i;
05035     rperm[i] = rperm[i + 1];
05036     rrank[rperm[i]] = i;
05037   }
05038   cperm[rank_r] = col_p;
05039   crank[col_p] = rank_r;
05040   rperm[rank_r] = row_p;
05041   rrank[row_p] = rank_r;
05042 }
05043 
05044 static int dbl_eliminate_row (
05045   dbl_factor_work * f,
05046   int rank_p,
05047   int rank_r)
05048 {
05049   dbl_ur_info *ur_inf = f->ur_inf;
05050   int *rperm = f->rperm;
05051   int *cperm = f->cperm;
05052   int *urindx = f->urindx;
05053   double *urcoef = f->urcoef;
05054   int *erindx = f->erindx;
05055   double *ercoef = f->ercoef;
05056   double *work_coef = f->work_coef;
05057   int er_freebeg = f->er_freebeg;
05058   int er_space = f->er_space;
05059   int beg;
05060   int nzcnt;
05061   int i;
05062   int j;
05063   int c;
05064   int r;
05065   double pivot_mul;
05066 
05067 #ifdef dbl_TRACK_FACTOR
05068   double max;
05069 
05070   dbl_EGlpNumInitVar (max);
05071   dbl_EGlpNumCopy (max, f->maxelem_cur);
05072 #endif /* dbl_TRACK_FACTOR */
05073   dbl_EGlpNumInitVar (pivot_mul);
05074 
05075   for (i = rank_p; i < rank_r; i++)
05076   {
05077     c = cperm[i];
05078     if (dbl_EGlpNumIsNeqZero (work_coef[c], f->fzero_tol))  /*
05079                                                          * if (work_coef[c] > fzero_tol || work_coef[c] < -fzero_tol) */
05080     {
05081       r = rperm[i];
05082       beg = ur_inf[r].rbeg;
05083       nzcnt = ur_inf[r].nzcnt;
05084       dbl_EGlpNumCopyFrac (pivot_mul, work_coef[c], urcoef[beg]);
05085       dbl_EGlpNumZero (work_coef[c]);
05086       for (j = 1; j < nzcnt; j++)
05087       {
05088         dbl_EGlpNumSubInnProdTo (work_coef[urindx[beg + j]], pivot_mul, urcoef[beg + j]); /* 0.85 */
05089       }
05090       if (er_freebeg >= er_space)
05091       {
05092         /* fprintf (stderr, "no space in dbl_eliminate_row\n"); */
05093 #ifdef dbl_TRACK_FACTOR
05094         dbl_EGlpNumClearVar (max);
05095 #endif
05096         dbl_EGlpNumClearVar (pivot_mul);
05097         return E_UPDATE_NOSPACE;
05098       }
05099       erindx[er_freebeg] = r;
05100       dbl_EGlpNumCopy (ercoef[er_freebeg], pivot_mul);
05101 #ifdef dbl_TRACK_FACTOR
05102       dbl_EGlpNumSetToMaxAbs (max, pivot_mul);
05103 #endif /* dbl_TRACK_FACTOR */
05104       er_freebeg++;
05105     }
05106     else
05107     {
05108       dbl_EGlpNumZero (work_coef[c]);
05109     }
05110   }
05111   f->er_freebeg = er_freebeg;
05112 #ifdef dbl_TRACK_FACTOR
05113   dbl_EGlpNumCopy (f->maxelem_cur, max);
05114   dbl_EGlpNumClearVar (max);
05115 #endif /* dbl_TRACK_FACTOR */
05116   dbl_EGlpNumClearVar (pivot_mul);
05117   return 0;
05118 }
05119 
05120 static int dbl_create_row (
05121   dbl_factor_work * f,
05122   double * a,
05123   int row,
05124   int minrank)
05125 {
05126   int *cperm = f->cperm;
05127   int dim = f->dim;
05128   int i;
05129   int j;
05130   int rval = 0;
05131 
05132 #ifdef dbl_TRACK_FACTOR
05133   double max;
05134 
05135