/* $Id$ */ /* Copyright (C) 1987, 2009, International Business Machines Corporation and others. All Rights Reserved. This code is licensed under the terms of the Eclipse Public License (EPL). */ /* CLP_OSL - if defined use osl 0 - don't unroll 2 and 3 - don't use in Gomory 1 - don't unroll - do use in Gomory 2 - unroll - don't use in Gomory 3 - unroll and use in Gomory */ #include "CoinOslFactorization.hpp" #include "CoinOslC.h" #include "CoinFinite.hpp" #ifndef NDEBUG extern int ets_count; extern int ets_check; #endif #define COIN_REGISTER register #define COIN_REGISTER2 #define COIN_REGISTER3 register #ifdef COIN_USE_RESTRICT # define COIN_RESTRICT2 __restrict #else # define COIN_RESTRICT2 #endif static int c_ekkshfpo_scan2zero(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact,const int * COIN_RESTRICT mpermu, double *COIN_RESTRICT worki, double *COIN_RESTRICT worko, int * COIN_RESTRICT mptr) { /* Local variables */ int irow; double tolerance = fact->zeroTolerance; int nin=fact->nrow; int * COIN_RESTRICT mptrX=mptr; if ((nin&1)!=0) { irow=1; if (fact->packedMode) { int irow0= *mpermu; double dval; assert (irow0>=1&&irow0<=nin); mpermu++; dval=worki[irow0]; if (NOT_ZERO(dval)) { worki[irow0]=0.0; if (fabs(dval) >= tolerance) { *(worko++)=dval; *(mptrX++) = 0; } } } else { int irow0= *mpermu; double dval; assert (irow0>=1&&irow0<=nin); mpermu++; dval=worki[irow0]; if (NOT_ZERO(dval)) { worki[irow0]=0.0; if (fabs(dval) >= tolerance) { *worko=dval; *(mptrX++) = 0; } } worko++; } } else { irow=0; } if (fact->packedMode) { for (; irow < nin; irow+=2) { int irow0,irow1; double dval0,dval1; irow0=mpermu[0]; irow1=mpermu[1]; assert (irow0>=1&&irow0<=nin); assert (irow1>=1&&irow1<=nin); dval0=worki[irow0]; dval1=worki[irow1]; if (NOT_ZERO(dval0)) { worki[irow0]=0.0; if (fabs(dval0) >= tolerance) { *(worko++)=dval0; *(mptrX++) = irow+0; } } if (NOT_ZERO(dval1)) { worki[irow1]=0.0; if (fabs(dval1) >= tolerance) { *(worko++)=dval1; *(mptrX++) = irow+1; } } mpermu+=2; } } else { for (; irow < nin; irow+=2) { int irow0,irow1; double dval0,dval1; irow0=mpermu[0]; irow1=mpermu[1]; assert (irow0>=1&&irow0<=nin); assert (irow1>=1&&irow1<=nin); dval0=worki[irow0]; dval1=worki[irow1]; if (NOT_ZERO(dval0)) { worki[irow0]=0.0; if (fabs(dval0) >= tolerance) { worko[0]=dval0; *(mptrX++) = irow+0; } } if (NOT_ZERO(dval1)) { worki[irow1]=0.0; if (fabs(dval1) >= tolerance) { worko[1]=dval1; *(mptrX++) = irow+1; } } mpermu+=2; worko+=2; } } return static_cast(mptrX-mptr); } /* * c_ekkshfpi_list executes the following loop: * * for (k=nincol, i=1; k; k--, i++) { * int ipt = mptr[i]; * int irow = mpermu[ipt]; * worko[mpermu[irow]] = worki[i]; * worki[i] = 0.0; * } */ static int c_ekkshfpi_list(const int *COIN_RESTRICT mpermu, double *COIN_RESTRICT worki, double *COIN_RESTRICT worko, const int * COIN_RESTRICT mptr, int nincol, int * lastNonZero) { int i,k,irow0,irow1; int first=COIN_INT_MAX; int last=0; /* worko was zeroed out outside */ k = nincol; i = 0; if ((k&1)!=0) { int ipt=mptr[i]; irow0=mpermu[ipt]; first = CoinMin(irow0,first); last = CoinMax(irow0,last); i++; worko[irow0]=*worki; *worki++=0.0; } k=k>>1; for (; k; k--) { int ipt0 = mptr[i]; int ipt1 = mptr[i+1]; irow0 = mpermu[ipt0]; irow1 = mpermu[ipt1]; i+=2; first = CoinMin(irow0,first); last = CoinMax(irow0,last); first = CoinMin(irow1,first); last = CoinMax(irow1,last); worko[irow0] = worki[0]; worko[irow1] = worki[1]; worki[0]=0.0; worki[1]=0.0; worki+=2; } *lastNonZero=last; return first; } /* * c_ekkshfpi_list2 executes the following loop: * * for (k=nincol, i=1; k; k--, i++) { * int ipt = mptr[i]; * int irow = mpermu[ipt]; * worko[mpermu[irow]] = worki[ipt]; * worki[ipt] = 0.0; * } */ static int c_ekkshfpi_list2(const int *COIN_RESTRICT mpermu, double *COIN_RESTRICT worki, double *COIN_RESTRICT worko, const int * COIN_RESTRICT mptr, int nincol, int * lastNonZero) { #if 1 int i,k,irow0,irow1; int first=COIN_INT_MAX; int last=0; /* worko was zeroed out outside */ k = nincol; i = 0; if ((k&1)!=0) { int ipt=mptr[i]; irow0=mpermu[ipt]; first = CoinMin(irow0,first); last = CoinMax(irow0,last); i++; worko[irow0]=worki[ipt]; worki[ipt]=0.0; } k=k>>1; for (; k; k--) { int ipt0 = mptr[i]; int ipt1 = mptr[i+1]; irow0 = mpermu[ipt0]; irow1 = mpermu[ipt1]; i+=2; first = CoinMin(irow0,first); last = CoinMax(irow0,last); first = CoinMin(irow1,first); last = CoinMax(irow1,last); worko[irow0] = worki[ipt0]; worko[irow1] = worki[ipt1]; worki[ipt0]=0.0; worki[ipt1]=0.0; } #else int first=COIN_INT_MAX; int last=0; /* worko was zeroed out outside */ for (int i=0; i>1; for (; k; k--) { int ipt0 = mptr[i]; int ipt1 = mptr[i+1]; irow0 = mpermu[ipt0]; irow1 = mpermu[ipt1]; mptr[i] = irow0; mptr[i+1] = irow1; i+=2; worko[irow0] = worki[0]; worko[irow1] = worki[1]; worki[0]=0.0; worki[1]=0.0; worki+=2; } } static int c_ekkscmv(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact,int n, double *COIN_RESTRICT dwork, int *COIN_RESTRICT mptr, double *COIN_RESTRICT dwork2) { double tolerance = fact->zeroTolerance; int irow; const int * COIN_RESTRICT mptrsave = mptr; double * COIN_RESTRICT dwhere = dwork+1; if ((n&1)!=0) { if (NOT_ZERO(*dwhere)) { if (fabs(*dwhere) >= tolerance) { *++dwork2 = *dwhere; *++mptr = SHIFT_INDEX(1); } else { *dwhere = 0.0; } } dwhere++; irow=2; } else { irow=1; } for (n=n>>1;n;n--) { int second = NOT_ZERO(*(dwhere+1)); if (NOT_ZERO(*dwhere)) { if (fabs(*dwhere) >= tolerance) { *++dwork2 = *dwhere; *++mptr = SHIFT_INDEX(irow); } else { *dwhere = 0.0; } } if (second) { if (fabs(*(dwhere+1)) >= tolerance) { *++dwork2 = *(dwhere+1); *++mptr = SHIFT_INDEX(irow+1); } else { *(dwhere+1) = 0.0; } } dwhere+=2; irow+=2; } return static_cast(mptr-mptrsave); } /* c_ekkscmv */ double c_ekkputl(const EKKfactinfo * COIN_RESTRICT2 fact, const int *COIN_RESTRICT mpt2, double *COIN_RESTRICT dwork1, double del3, int nincol, int nuspik) { double * COIN_RESTRICT dwork3 = fact->xeeadr+fact->nnentu; int * COIN_RESTRICT hrowi = fact->xeradr+fact->nnentu; int offset = fact->R_etas_start[fact->nR_etas+1]; int *COIN_RESTRICT hrowiR = fact->R_etas_index+offset; double *COIN_RESTRICT dluval = fact->R_etas_element+offset; int i, j; /* dwork1 is r', the new R transform * dwork3 is the updated incoming column, alpha_p * del3 apparently has the pivot of the incoming column (???). * Here, we compute the p'th element of R^-1 alpha_p * (as described on p. 273), which is just a dot product. * I don't know why we subtract. */ for (i = 1; i <= nuspik; ++i) { j = UNSHIFT_INDEX(hrowi[ i]); del3 -= dwork3[i] * dwork1[j]; } /* here we finally copy the r' to where we want it, the end */ /* also take into account that the p'th row of R^-1 is -(p'th row of R). */ /* also zero out dwork1 as we go */ for (i = 0; i < nincol; ++i) { j = mpt2[i]; hrowiR[ - i ] = SHIFT_INDEX(j); dluval[ - i ] = -dwork1[j]; dwork1[j] = 0.; } return del3; } /* c_ekkputl */ /* making this static seems to slow code down! may be being inlined */ int c_ekkputl2( const EKKfactinfo * COIN_RESTRICT2 fact, double *COIN_RESTRICT dwork1, double *del3p, int nuspik) { double * COIN_RESTRICT dwork3 = fact->xeeadr+fact->nnentu; int * COIN_RESTRICT hrowi = fact->xeradr+fact->nnentu; int offset = fact->R_etas_start[fact->nR_etas+1]; int *COIN_RESTRICT hrowiR = fact->R_etas_index+offset; double *COIN_RESTRICT dluval = fact->R_etas_element+offset; int i, j; #if 0 int nincol=c_ekksczr(fact,fact->nrow,dwork1,hrowiR); #else int nrow=fact->nrow; const double tolerance = fact->zeroTolerance; int * COIN_RESTRICT mptrX=hrowiR; for (i = 1; i <= nrow; ++i) { if (dwork1[i] != 0.) { if (fabs(dwork1[i]) >= tolerance) { *(mptrX--) = SHIFT_INDEX(i); } else { dwork1[i] = 0.0; } } } int nincol=static_cast(hrowiR-mptrX); #endif double del3 = *del3p; /* dwork1 is r', the new R transform * dwork3 is the updated incoming column, alpha_p * del3 apparently has the pivot of the incoming column (???). * Here, we compute the p'th element of R^-1 alpha_p * (as described on p. 273), which is just a dot product. * I don't know why we subtract. */ for (i = 1; i <= nuspik; ++i) { j = UNSHIFT_INDEX(hrowi[ i]); del3 -= dwork3[i] * dwork1[j]; } /* here we finally copy the r' to where we want it, the end */ /* also take into account that the p'th row of R^-1 is -(p'th row of R). */ /* also zero out dwork1 as we go */ for (i = 0; i < nincol; ++i) { j = UNSHIFT_INDEX(hrowiR[-i]); dluval[ - i ] = -dwork1[j]; dwork1[j] = 0.; } *del3p = del3; return nincol; } /* c_ekkputl */ static void c_ekkbtj4p_no_dense(const int nrow,const double * COIN_RESTRICT dluval, const int * COIN_RESTRICT hrowi, const int * COIN_RESTRICT mcstrt, double * COIN_RESTRICT dwork1, int ndo,int jpiv) { int i; double dv1; int iel; int irow; int i1,i2; /* count down to first nonzero */ for (i=nrow;i >=1;i--) { if (dwork1[i]) { break; } } i--; /* as pivot is just 1.0 */ if (i>ndo+jpiv) { i=ndo+jpiv; } mcstrt -= jpiv; i2=mcstrt[i+1]; for (; i > jpiv; --i) { double dv1b=0.0; int nel; i1 = mcstrt[i]; nel= i1-i2; dv1 = dwork1[i]; iel=i2; if ((nel&1)!=0) { irow = hrowi[iel]; dv1b = SHIFT_REF(dwork1, irow) * dluval[iel]; iel++; } for ( ; iel < i1; iel+=2) { int irow = hrowi[iel]; int irowb = hrowi[iel+1]; dv1 += SHIFT_REF(dwork1, irow) * dluval[iel]; dv1b += SHIFT_REF(dwork1, irowb) * dluval[iel+1]; } i2=i1; dwork1[i] = dv1+dv1b; } } /* c_ekkbtj4 */ static int c_ekkbtj4p_dense(const int nrow,const double * COIN_RESTRICT dluval, const int * COIN_RESTRICT hrowi, const int * COIN_RESTRICT mcstrt, double * COIN_RESTRICT dwork1, int ndenuc, int ndo,int jpiv) { int i; int i2; int last=ndo-ndenuc+1; double * COIN_RESTRICT densew = &dwork1[nrow-1]; int nincol=0; const double * COIN_RESTRICT dlu1; dluval--; hrowi--; /* count down to first nonzero */ for (i=nrow;i >=1;i--) { if (dwork1[i]) { break; } } if (ilast; i-=2) { int k; double dv1,dv2; const double * COIN_RESTRICT dlu2; dv1=densew[1]; dlu2=dlu1+nincol; dv2=densew[0]; for (k=0;k jpiv+1; i-=2) { int i1 = mcstrt[i]; double dv1 = dwork1[i]; double dv2; for (; iel < i1; iel++) { int irow = hrowi[iel]; dv1 += SHIFT_REF(dwork1, irow) * dluval[iel]; } i1 = mcstrt[i-1]; dv2 = dwork1[i-1]; dwork1[i] = dv1; for (; iel < i1; iel++) { int irow = hrowi[iel]; dv2 += SHIFT_REF(dwork1, irow) * dluval[iel]; } dwork1[i-1] = dv2; } if (i>jpiv) { int i1 = mcstrt[i]; double dv1 = dwork1[i]; for (; iel < i1; iel++) { int irow = hrowi[iel]; dv1 += SHIFT_REF(dwork1, irow) * dluval[iel]; } dwork1[i] = dv1; } } static void c_ekkbtj4p(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1) { int lstart=fact->lstart; const int * COIN_RESTRICT hpivco = fact->kcpadr; const double * COIN_RESTRICT dluval = fact->xeeadr+1; const int * COIN_RESTRICT hrowi = fact->xeradr+1; const int * COIN_RESTRICT mcstrt = fact->xcsadr+lstart-1; int jpiv=hpivco[lstart]-1; int ndo=fact->xnetalval; /* see if dense enough to unroll */ if (fact->ndenuc<5) { c_ekkbtj4p_no_dense(fact->nrow,dluval,hrowi,mcstrt,dwork1,ndo,jpiv); } else { int i = c_ekkbtj4p_dense(fact->nrow,dluval,hrowi,mcstrt,dwork1, fact->ndenuc, ndo,jpiv); c_ekkbtj4p_after_dense(dluval,hrowi,mcstrt,dwork1,i,jpiv); } } /* c_ekkbtj4p */ static int c_ekkbtj4_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, /* C style */ double * COIN_RESTRICT dworko, int nincol, int * COIN_RESTRICT spare) { const int nrow = fact->nrow; const int * COIN_RESTRICT hcoli = fact->xecadr; const int * COIN_RESTRICT mrstrt = fact->xrsadr+nrow; char * COIN_RESTRICT nonzero = fact->nonzero; const int * COIN_RESTRICT hpivro = fact->krpadr; const double * COIN_RESTRICT de2val = fact->xe2adr-1; double tolerance = fact->zeroTolerance; double dv; int iel; int k,nStack,kx; int nList=0; int * COIN_RESTRICT list = spare; int * COIN_RESTRICT stack = spare+nrow; int * COIN_RESTRICT next = stack+nrow; int iPivot,kPivot; int iput,nput=0,kput=nrow; int j; int firstDoRow=fact->firstDoRow; for (k=0;k=firstDoRow) { stack[0]=iPivot; next[0]=mrstrt[iPivot]; while (nStack) { /* take off stack */ kPivot=stack[--nStack]; if (nonzero[kPivot]!=1&&kPivot>=firstDoRow) { j=next[nStack]; if (j==mrstrt[kPivot+1]) { /* finished so mark */ list[nList++]=kPivot; nonzero[kPivot]=1; } else { kPivot=hcoli[j]; /* put back on stack */ next[nStack++] ++; if (!nonzero[kPivot]) { /* and new one */ stack[nStack]=kPivot; nonzero[kPivot]=2; next[nStack++]=mrstrt[kPivot]; } } } else if (kPivotpackedMode) { dworko++; for (k=nList-1;k>=0;k--) { double dv; iPivot = list[k]; dv = dwork1[iPivot]; dwork1[iPivot]=0.0; nonzero[iPivot]=0; if (fabs(dv) > tolerance) { iput=hpivro[iPivot]; kx=mrstrt[iPivot]; dworko[nput]=dv; for (iel = kx; iel < mrstrt[iPivot+1]; iel++) { double dval; int irow = hcoli[iel]; dval=de2val[iel]; dwork1[irow] += dv*dval; } mpt[nput++]=iput-1; } else { dwork1[iPivot]=0.0; /* force to zero, not just near zero */ } } /* check remainder */ for (k=kput;k tolerance) { dworko[nput]=dv; mpt[nput++]=iput-1; } } } else { /* not packed */ for (k=nList-1;k>=0;k--) { double dv; iPivot = list[k]; dv = dwork1[iPivot]; dwork1[iPivot]=0.0; nonzero[iPivot]=0; if (fabs(dv) > tolerance) { iput=hpivro[iPivot]; kx=mrstrt[iPivot]; dworko[iput]=dv; for (iel = kx; iel < mrstrt[iPivot+1]; iel++) { double dval; int irow = hcoli[iel]; dval=de2val[iel]; dwork1[irow] += dv*dval; } mpt[nput++]=iput-1; } else { dwork1[iPivot]=0.0; /* force to zero, not just near zero */ } } /* check remainder */ for (k=kput;k tolerance) { dworko[iput]=dv; mpt[nput++]=iput-1; } } } return (nput); } /* c_ekkbtj4 */ static void c_ekkbtjl(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1) { int i, j, k, k1; int l1; const double * COIN_RESTRICT dluval = fact->R_etas_element; const int * COIN_RESTRICT hrowi = fact->R_etas_index; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; const int * COIN_RESTRICT hpivco = fact->hpivcoR; int ndo=fact->nR_etas; #ifndef UNROLL1 #define UNROLL1 4 #endif #if UNROLL1>2 int l2; #endif int kn; double dv; int iel; int ipiv; int knext; knext = mcstrt[ndo + 1]; #if UNROLL1>2 for (i = ndo; i > 0; --i) { k1 = knext; knext = mcstrt[i]; ipiv = hpivco[i]; dv = dwork1[ipiv]; /* fast floating */ k = knext - k1; kn = k >> 2; iel = k1 + 1; if (dv != 0.) { l1 = (k & 1) != 0; l2 = (k & 2) != 0; for (j = 1; j <= kn; j++) { int irow0 = hrowi[iel + 0]; int irow1 = hrowi[iel + 1]; int irow2 = hrowi[iel + 2]; int irow3 = hrowi[iel + 3]; double dval0 = dv * dluval[iel + 0] + SHIFT_REF(dwork1, irow0); double dval1 = dv * dluval[iel + 1] + SHIFT_REF(dwork1, irow1); double dval2 = dv * dluval[iel + 2] + SHIFT_REF(dwork1, irow2); double dval3 = dv * dluval[iel + 3] + SHIFT_REF(dwork1, irow3); SHIFT_REF(dwork1, irow0) = dval0; SHIFT_REF(dwork1, irow1) = dval1; SHIFT_REF(dwork1, irow2) = dval2; SHIFT_REF(dwork1, irow3) = dval3; iel+=4; } if (l1) { int irow0 = hrowi[iel]; SHIFT_REF(dwork1, irow0) += dv* dluval[iel]; ++iel; } if (l2) { int irow0 = hrowi[iel + 0]; int irow1 = hrowi[iel + 1]; SHIFT_REF(dwork1, irow0) += dv* dluval[iel]; SHIFT_REF(dwork1, irow1) += dv* dluval[iel+1]; } } } #else for (i = ndo; i > 0; --i) { k1 = knext; knext = mcstrt[i]; ipiv = hpivco[i]; dv = dwork1[ipiv]; k = knext - k1; kn = k >> 1; iel = k1 + 1; if (dv != 0.) { l1 = (k & 1) != 0; for (j = 1; j <= kn; j++) { int irow0 = hrowi[iel + 0]; int irow1 = hrowi[iel + 1]; double dval0 = dv * dluval[iel + 0] + SHIFT_REF(dwork1, irow0); double dval1 = dv * dluval[iel + 1] + SHIFT_REF(dwork1, irow1); SHIFT_REF(dwork1, irow0) = dval0; SHIFT_REF(dwork1, irow1) = dval1; iel+=2; } if (l1) { int irow0 = hrowi[iel]; SHIFT_REF(dwork1, irow0) += dv* dluval[iel]; ++iel; } } } #endif } /* c_ekkbtjl */ static int c_ekkbtjl_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt , int nincol) { const double * COIN_RESTRICT dluval = fact->R_etas_element; const int * COIN_RESTRICT hrowi = fact->R_etas_index; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; const int * COIN_RESTRICT hpivco = fact->hpivcoR; char * COIN_RESTRICT nonzero = fact->nonzero; int ndo=fact->nR_etas; int i, j, k1; double dv; int ipiv; int irow0, irow1; int knext; int number=nincol; /* ------------------------------------------- */ /* adjust back */ hrowi++; dluval++; /* DO ANY ROW TRANSFORMATIONS */ /* Function Body */ knext = mcstrt[ndo + 1]; for (i = ndo; i > 0; --i) { k1 = knext; knext = mcstrt[i]; ipiv = hpivco[i]; dv = dwork1[ipiv]; if (dv) { for (j = k1; j 1 const int * hrowi2=hrowi+kx; const int * hrowi2end=hrowi2+nel; const double * dluval2=dluval+kx; #else int iel; #endif const double dpiv = dluval[kx-1]; /* inverse of pivot */ /* subtract terms whose unknowns have been solved for */ /* a significant proportion of these loops may not modify dv at all. * However, it seems to be just as expensive to check if the loop * would modify dv as it is to just do it. * The only difference would be that dluval wouldn't be referenced * for those loops, would might save some cache paging, * but unfortunately the code generated to search for zeros (on AIX) * is *worse* than code that just multiplies by dval. */ #if UNROLL2<2 for (iel = kx; iel < kxe; ++iel) { const int irow = hrowi[iel]; const double dval=dluval[iel]; dv -= SHIFT_REF(dwork1, irow) * dval; } dwork1[ipiv] = dv * dpiv; /* divide by the pivot */ #else if ((nel&1)!=0) { int irow = *hrowi2; double dval=*dluval2; dv -= SHIFT_REF(dwork1, irow) * dval; hrowi2++; dluval2++; } for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) { int irow0 = hrowi2[0]; int irow1 = hrowi2[1]; double dval0=dluval2[0]; double dval1=dluval2[1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); dv -= d0 * dval0; dv -= d1 * dval1; } dwork1[ipiv] = dv * dpiv; /* divide by the pivot */ #endif ipiv=hpivco[ipiv]; } return (ipiv); } /* * We are given the upper diagonal matrix U from the LU factorization * and a rhs dwork1. * This solves the system U x = dwork1 * by back substitution, overwriting dwork1 with the solution x. * * It does this in textbook style by solving the equations "bottom" up, * so for each equation one new unknown is solved for by subtracting * from the rhs the sum of the terms whose unknowns have been solved for, * then dividing by the coefficient of the new unknown. * * Since we update the U matrix using F-T, the order of the columns * changes slightly each iteration. Initially, hpivco[i] == i+1, * and each iteration (generally) introduces one element where this * is no longer true. However, because we periodically refactorize, * it is much more common for hpivco[i] == i+1 than not. * * The one quirk is that value referred to as the pivot is actually * the reciprocal of the pivot, to avoid a division. * * Solving in this fashion is inappropriate if there are frequently * cases where all unknowns in an equation have value zero. * This seems to happen frequently if the sparsity of the rhs is, say, 10%. */ static void c_ekkbtju(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int ipiv) { const int nrow = fact->nrow; double * COIN_RESTRICT dluval = fact->xeeadr; int * COIN_RESTRICT hrowi = fact->xeradr; int * COIN_RESTRICT mcstrt = fact->xcsadr; int * COIN_RESTRICT hpivco_new = fact->kcpadr+1; int ndenuc=fact->ndenuc; int first_dense = fact->first_dense; int last_dense = fact->last_dense; const int has_dense = (first_densek1;j--) { int irow=UNSHIFT_INDEX(hrowi[j]); if (irow (hpivco_new), dwork1,&ipiv,last_dense, n - first_dense, densew); } (void) c_ekkbtju_aux(dluval, hrowi, mcstrt, hpivco_new, dwork1, ipiv, nrow); } /* c_ekkbtju */ /* * mpt / *nincolp contain the indices of nonzeros in dwork1. * nonzero contains the same information as a byte-mask. * * currently, erase_nonzero is true iff this is called from c_ekketsj. */ static int c_ekkbtju_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int nincol, int * COIN_RESTRICT spare) { const double * COIN_RESTRICT dluval = fact->xeeadr+1; const int * COIN_RESTRICT mcstrt = fact->xcsadr; char * COIN_RESTRICT nonzero = fact->nonzero; const int * COIN_RESTRICT hcoli = fact->xecadr; const int * COIN_RESTRICT mrstrt = fact->xrsadr; const int * COIN_RESTRICT hinrow = fact->xrnadr; const double * COIN_RESTRICT de2val = fact->xe2adr-1; int i; int iPivot; int nList=0; int nStack,k,kx; const int nrow=fact->nrow; const double tolerance = fact->zeroTolerance; int * COIN_RESTRICT list = spare; int * COIN_RESTRICT stack = spare+nrow; int * COIN_RESTRICT next = stack+nrow; /* * Examine all nonzero elements and determine which elements may be * nonzero in the result. * Any row in U that contains terms that may have nonzero variable values * may produce a nonzero value. */ for (k=0;k=0;i--) { double dpiv; double dv; iPivot = list[i]; kx = mcstrt[iPivot]; dpiv = dluval[kx-1]; dv = dpiv * dwork1[iPivot]; nonzero[iPivot] = 0; if (fabs(dv)>=tolerance) { int iel; int krx = mrstrt[iPivot]; int krxe = krx+hinrow[iPivot]; dwork1[iPivot]=dv; mpt[nList++]=iPivot; for (iel = krx; iel < krxe; iel++) { int irow0 = hcoli[iel]; double dval=de2val[iel]; dwork1[irow0] -= dv*dval; } } else { dwork1[iPivot]=0.0; } } return (nList); } /* c_ekkbtjuRow */ /* * dpermu is supposed to be zeroed on entry to this routine. * It is used as a working buffer. * The input vector dwork1 is permuted into dpermu, operated on, * and the answer is permuted back into dwork1, zeroing dpermu in * the process. */ /* * nincol > 0 ==> mpt contains indices of non-zeros in dpermu * * first_nonzero contains index of first (last??)nonzero; * only used if nincol==0. * * dpermu contains permuted input; dwork1 is now zero */ int c_ekkbtrn(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int first_nonzero) { double * COIN_RESTRICT dpermu = fact->kadrpm; const int * COIN_RESTRICT mpermu=fact->mpermu; const int * COIN_RESTRICT hpivco_new= fact->kcpadr+1; const int nrow = fact->nrow; int i; int nincol; /* find the first non-zero input */ int ipiv; if (first_nonzero) { ipiv = first_nonzero; #if 1 if (c_ekk_IsSet(fact->bitArray,ipiv)) { /* slack */ int lastSlack = fact->lastSlack; int firstDo=hpivco_new[lastSlack]; assert (dpermu[ipiv]); while (ipiv!=firstDo) { assert (c_ekk_IsSet(fact->bitArray,ipiv)); if (dpermu[ipiv]) dpermu[ipiv]=-dpermu[ipiv]; ipiv=hpivco_new[ipiv]; } } #endif } else { int lastSlack = fact->numberSlacks; ipiv=hpivco_new[0]; for (i=0;ibitArray,ipiv)); if (dpermu[ipiv]) { break; } else { ipiv=next_piv; } } /* usually, there is a non-zero slack entry... */ if (i==lastSlack) { /* but if there isn't... */ for (;ibitArray,ipiv)); if (dpermu[ipiv]) dpermu[ipiv]=-dpermu[ipiv]; ipiv=hpivco_new[ipiv]; } assert (!c_ekk_IsSet(fact->bitArray,ipiv)||ipiv>fact->nrow); /* this is presumably the first non-zero non slack */ /*ipiv=firstDo;*/ } } if (ipiv<=fact->nrow) { /* skipBtju is always (?) 0 first the first call, * ipiv tends to be >nrow for the second */ /* DO U */ c_ekkbtju(fact,dpermu, ipiv); } /* DO ROW ETAS IN L */ c_ekkbtjl(fact, dpermu); c_ekkbtj4p(fact,dpermu); /* dwork1[mpermu] = dpermu; dpermu = 0; mpt = indices of non-zeros */ nincol = c_ekkshfpo_scan2zero(fact,&mpermu[1],dpermu,&dwork1[1],&mpt[1]); /* dpermu should be zero now */ #ifdef DEBUG for (i=1;i<=nrow ;i++ ) { if (dpermu[i]) { abort(); } /* endif */ } /* endfor */ #endif return (nincol); } /* c_ekkbtrn */ static int c_ekkbtrn0_new(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int nincol, int * COIN_RESTRICT spare) { double * COIN_RESTRICT dpermu = fact->kadrpm; const int * COIN_RESTRICT mpermu=fact->mpermu; const int * COIN_RESTRICT hpivro = fact->krpadr; const int nrow = fact->nrow; int i; char * nonzero=fact->nonzero; int doSparse=1; /* so: dpermu must contain room for: * nrow doubles, followed by * nrow ints (mpermu), followed by * nrow ints (the inverse permutation), followed by * an unused area (?) of nrow ints, followed by * nrow chars (this non-zero array). * * and apparently the first nrow elements of nonzero are expected * to already be zero. */ #ifdef DEBUG for (i=1;i<=nrow ;i++ ) { if (nonzero[i]) { abort(); } /* endif */ } /* endfor */ #endif /* now nonzero[i]==1 iff there is an entry for i in mpt */ nincol=c_ekkbtju_sparse(fact, dpermu, &mpt[1], nincol, spare); /* the vector may have more nonzero elements now */ /* DO ROW ETAS IN L */ #define DENSE_THRESHOLD (nincol*10+100) if (DENSE_THRESHOLD>nrow) { doSparse=0; c_ekkbtjl(fact, dpermu); } else { /* set nonzero */ for(i=0;inrow) { doSparse=0; #ifdef DEBUG for (i=1;i<=nrow;i++) { if (nonzero[i]) { abort(); } } #endif } } if (!doSparse) { c_ekkbtj4p(fact,dpermu); /* dwork1[mpermu] = dpermu; dpermu = 0; mpt = indices of non-zeros */ nincol = c_ekkshfpo_scan2zero(fact,&mpermu[1],dpermu,&dwork1[1],&mpt[1]); /* dpermu should be zero now */ #ifdef DEBUG for (i=1;i<=nrow ;i++ ) { if (dpermu[i]) { abort(); } /* endif */ } /* endfor */ #endif } else { /* still sparse */ if (fact->nnentl) { nincol = c_ekkbtj4_sparse(fact, dpermu, &mpt[1], dwork1, nincol,spare); } else { double tolerance=fact->zeroTolerance; int irow; int nput=0; if (fact->packedMode) { for (i = 0; i = tolerance) { irow0= hpivro[irow]; dwork1[1+nput]=dval; mpt[1 + nput++]=irow0-1; } dpermu[irow]=0.0; } } } else { for (i = 0; i = tolerance) { irow0= hpivro[irow]; dwork1[irow0]=dval; mpt[1 + nput++]=irow0-1; } dpermu[irow]=0.0; } } } nincol=nput; } } return (nincol); } /* c_ekkbtrn */ /* returns c_ekkbtrn(fact, dwork1, mpt) * * but since mpt[1..nincol] contains the indices of non-zeros in dwork1, * we can do faster. */ static int c_ekkbtrn_mpt(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int nincol,int * COIN_RESTRICT spare) { double * COIN_RESTRICT dpermu = fact->kadrpm; const int nrow = fact->nrow; const int * COIN_RESTRICT mpermu=fact->mpermu; /*const int *mrstrt = fact->xrsadr;*/ #ifdef DEBUG int i; memset(spare,'A',3*nrow*sizeof(int)); { for (i=1;i<=nrow;i++) { if (dpermu[i]) { abort(); } } } #endif int i; #ifdef DEBUG for (i=1;i<=nrow;i++) { if (fact->nonzero[i]||dpermu[i]) { abort(); } } #endif assert (fact->if_sparse_update>0&&mpt&&fact->rows_ok) ; /* read the input vector from mpt/dwork1; * permute it into dpermu; * construct a nonzero mask in nonzero; * overwrite mpt with the permuted indices; * clear the dwork1 vector. */ for (i=0;iif_sparse_update>0) { for (i=1;i<=nrow;i++) { if (fact->nonzero[i]) { abort(); } } } } #endif return nincol; } /* returns c_ekkbtrn(fact, dwork1, mpt) * * but since (dwork1[i]!=0) == (i==ipivrw), * we can do faster. */ int c_ekkbtrn_ipivrw(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int ipivrw,int * COIN_RESTRICT spare) { double * COIN_RESTRICT dpermu = fact->kadrpm; const int nrow = fact->nrow; const int * COIN_RESTRICT mpermu=fact->mpermu; const double * COIN_RESTRICT dluval = fact->xeeadr; const int * COIN_RESTRICT mrstrt = fact->xrsadr; const int * COIN_RESTRICT hinrow = fact->xrnadr; const int * COIN_RESTRICT hcoli = fact->xecadr; const int * COIN_RESTRICT mcstrt = fact->xcsadr; int nincol; #ifdef DEBUG int i; for (i=1;i<=nrow ;i++ ) { if (dpermu[i]) { abort(); } /* endif */ } /* endfor */ #endif if (fact->if_sparse_update>0&&mpt&& fact->rows_ok) { mpt[1] = ipivrw; nincol = c_ekkbtrn_mpt(fact, dwork1, mpt, 1,spare); } else { int ipiv; int kpivrw = mpermu[ipivrw]; dpermu[kpivrw]=dwork1[ipivrw]; dwork1[ipivrw]=0.0; if (fact->rows_ok) { /* !fact->if_sparse_update * but we still have rowwise info, * so we may as well use it to do the slack row */ int iipivrw=nrow+1; int itest = fact->nnentu+1; int k=mrstrt[kpivrw]; int lastInRow= k+hinrow[kpivrw]; double dpiv,dv; for (;knrow) { if (c_ekk_IsSet(fact->bitArray,ipiv)) { const int * hpivco_new= fact->kcpadr+1; int lastSlack = fact->lastSlack; int firstDo=hpivco_new[lastSlack]; /* slack */ /* need pivot row of first nonslack */ dpermu[ipiv]=-dpermu[ipiv]; #ifndef NDEBUG while (1) { assert (c_ekk_IsSet(fact->bitArray,ipiv)); ipiv=hpivco_new[ipiv]; if (ipiv>fact->nrow||ipiv==firstDo) break; } assert (!c_ekk_IsSet(fact->bitArray,ipiv)||ipiv>fact->nrow); assert (ipiv==firstDo); #endif ipiv=firstDo; } } nincol = c_ekkbtrn(fact, dwork1, mpt, ipiv); } return nincol; } /* * Does work associated with eq. 3.7: * r' = u' U^-1 * * where u' (can't write the overbar) is the p'th row of U, without * the entry for column p. (here, jpivrw is p). * We solve this as for btju. We know * r' U = u' * * so we solve from low index to hi, determining the next value u_i' * by doing the dot-product of r' and the i'th column of U (excluding * element i itself), subtracting that from u'_i, and dividing by * U_ii (we store the reciprocal, so here we multiply). * * Now, in principle dwork1 should be initialized to the p'th row of U. * Instead, it is initially zeroed and filled in as we go along. * Of the entries in u' that we reference during a dot product with * a column of U, either * the entry is 0 by definition, since it is < p, or * it has already been set by a previous iteration, or * it is p. * * Because of this, we know that all elements < p will be zero; * that's why we start with p (kpivrw). * While we do this product, we also zero out the p'th row. */ static void c_ekketju_aux(COIN_REGISTER2 EKKfactinfo * COIN_RESTRICT2 fact,int sparse, double * COIN_RESTRICT dluval, int * COIN_RESTRICT hrowi, const int * COIN_RESTRICT mcstrt, const int * COIN_RESTRICT hpivco, double * COIN_RESTRICT dwork1, int *ipivp, int jpivrw, int stop_col) { int ipiv = *ipivp; if (1&&ipivbitArray,ipiv)) { /* slack */ int lastSlack = fact->lastSlack; int firstDo=hpivco[lastSlack]; while (1) { assert (c_ekk_IsSet(fact->bitArray,ipiv)); dwork1[ipiv] = -dwork1[ipiv]; ipiv=hpivco[ipiv]; /* next column - generally ipiv+1 */ if (ipiv==firstDo||ipiv>=stop_col) break; } } while(ipivnrow; if (first_dense < last_dense && mcstrt[ipiv] <= mcstrt[last_dense]) { /* There are dense columns, and * some dense columns precede the pivot column */ /* first do any sparse columns "on the left" */ c_ekketju_aux(fact, true, dluval, hrowi, mcstrt, hpivco, dwork1, &ipiv, jpivrw, first_dense); /* then do dense columns */ c_ekketju_aux(fact, false, dluval, hrowi, mcstrt, hpivco, dwork1, &ipiv, jpivrw, last_dense+1); /* final sparse columns "on the right" ...*/ } /* ...are the same as sparse columns if there are no dense */ c_ekketju_aux(fact, true, dluval, hrowi, mcstrt, hpivco, dwork1, &ipiv, jpivrw, nrow+1); } /* c_ekketju */ /*#define PRINT_DEBUG*/ /* dwork1 is assumed to be zeroed on entry */ int c_ekketsj(COIN_REGISTER2 /*const*/ EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt2, double dalpha, int orig_nincol, int npivot, int *nuspikp, const int ipivrw,int * spare) { int nuspik = *nuspikp; int * COIN_RESTRICT mpermu=fact->mpermu; int * COIN_RESTRICT hcoli = fact->xecadr; double * COIN_RESTRICT dluval = fact->xeeadr; int * COIN_RESTRICT mrstrt = fact->xrsadr; int * COIN_RESTRICT hrowi = fact->xeradr; int * COIN_RESTRICT mcstrt = fact->xcsadr; int * COIN_RESTRICT hinrow = fact->xrnadr; /*int *hincol = fact->xcnadr; int *hpivro = fact->krpadr;*/ int * COIN_RESTRICT hpivco = fact->kcpadr; double * COIN_RESTRICT de2val = fact->xe2adr; const int nrow = fact->nrow; const int ifRowCopy = fact->rows_ok; int i, j=-1, k, i1, i2, k1; int kc, iel; double del3; int nroom; bool ifrows= (mrstrt[1] != 0); int kpivrw, jpivrw; int first_dense_mcstrt,last_dense_mcstrt; int nnentl; /* includes row stuff */ int doSparse=(fact->if_sparse_update>0); #ifdef MORE_DEBUG { const int * COIN_RESTRICT hrowi = fact->R_etas_index; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; int ndo=fact->nR_etas; int knext; knext = mcstrt[ndo + 1]; for (int i = ndo; i > 0; --i) { int k1 = knext; knext = mcstrt[i]; for (int j = k1+1; j < knext; j++) { assert (hrowi[j]>0&&hrowi[j]<100000); } } } #endif int mcstrt_piv; int nincol=0; int * COIN_RESTRICT hpivco_new=fact->kcpadr+1; int * COIN_RESTRICT back=fact->back; int irtcod = 0; /* Parameter adjustments */ de2val--; /* Function Body */ if (!ifRowCopy) { doSparse=0; fact->if_sparse_update=-abs(fact->if_sparse_update); } if (npivot==1) { fact->num_resets=0; } kpivrw = mpermu[ipivrw]; #if 0 //ndef NDEBUG ets_count++; if (ets_check>=0&&ets_count>=ets_check) { printf("trouble\n"); } #endif mcstrt_piv=mcstrt[kpivrw]; /* ndenuc - top has number deleted */ if (fact->ndenuc) { first_dense_mcstrt = mcstrt[fact->first_dense]; last_dense_mcstrt = mcstrt[fact->last_dense]; } else { first_dense_mcstrt=0; last_dense_mcstrt=0; } { int kdnspt = fact->nnetas - fact->nnentl; i1 = ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]); /*i1 = -99999999;*/ /* fact->R_etas_start[fact->nR_etas + 1] is -(the number of els in R) */ nnentl = fact->nnetas - ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]); } fact->demark=fact->nnentu+nnentl; jpivrw = SHIFT_INDEX(kpivrw); #ifdef CLP_REUSE_ETAS double del3Orig=0.0; #endif if (nuspik < 0) { goto L7000; } else if (nuspik == 0) { del3 = 0.; } else { del3 = 0.; i1 = fact->nnentu + 1; i2 = fact->nnentu + nuspik; if (fact->sortedEta) { /* binary search */ if (hrowi[i2] == jpivrw) { /* sitting right on the end - easy */ del3 = dluval[i2]; --nuspik; } else { bool foundit = true; /* binary search - sort of implies hrowi is sorted */ i = i1; if (hrowi[i] != jpivrw) { while (1) { i = (i1 + i2) >>1; if (i == i1) { foundit = false; break; } if (hrowi[i] < jpivrw) { i1 = i; } else if (hrowi[i] > jpivrw) { i2 = i; } else break; } } /* ??? what if we didn't find it? */ if (foundit) { del3 = dluval[i]; --nuspik; /* remove it and move the last element into its place */ hrowi[i] = hrowi[nuspik + fact->nnentu+1]; dluval[i] = dluval[nuspik + fact->nnentu+1]; } } } else { /* search */ for (i=i1;i<=i2;i++) { if (hrowi[i] == jpivrw) { del3 = dluval[i]; --nuspik; /* remove it and move the last element into its place */ hrowi[i] = hrowi[i2]; dluval[i] = dluval[i2]; break; } } } } #ifdef CLP_REUSE_ETAS del3Orig=del3; #endif /* OLD COLUMN POINTERS */ /* **************************************************************** */ if (!ifRowCopy) { /* old method */ /* DO U */ c_ekketju(fact,dluval, hrowi, mcstrt, hpivco_new, dwork1, kpivrw,fact->first_dense, fact->last_dense); } else { /* could take out of old column but lets try being crude */ /* try taking out */ if (fact->xe2adr != 0&&doSparse) { /* * There is both a column and row representation of U. * For each row in the kpivrw'th column of the col U rep, * find its position in the U row rep and remove it * by overwriting it with the last element. */ int k1x = mcstrt[kpivrw]; int nel = hrowi[k1x]; /* yes, this is the nel, for the pivot */ int k2x = k1x + nel; for (k = k1x + 1; k <= k2x; ++k) { int irow = UNSHIFT_INDEX(hrowi[k]); int kx = mrstrt[irow]; int nel = hinrow[irow]-1; hinrow[irow]=nel; int jlast = kx + nel; for (int iel=kx;ielnnentu + 1; i2 = fact->nnentu + nuspik; int * COIN_RESTRICT eta_last=mpermu+nrow*2+3; int * COIN_RESTRICT eta_next=eta_last+nrow+2; if (fact->xe2adr == 0||!doSparse) { /* we have column indices by row, but not the actual values */ for (iel = i1; iel <= i2; ++iel) { int irow = UNSHIFT_INDEX(hrowi[iel]); int iput = hinrow[irow]; int kput = mrstrt[irow]; int nextRow=eta_next[irow]; assert (kput>0); kput += iput; if (kput < mrstrt[nextRow]) { /* there is room - append the pivot column; * this corresponds making alpha_p the rightmost column of U (p. 268)*/ hinrow[irow] = iput + 1; hcoli[kput] = kpivrw; } else { /* no room - switch off */ doSparse=0; /* possible kpivrw 1 */ k1 = mrstrt[kpivrw]; mrstrt[1]=-1; fact->rows_ok = false; goto L1226; } } } else { if (! doSparse) { /* we have both column indices and values by row */ /* just like loop above, but with extra assign to de2val */ for (iel = i1; iel <= i2; ++iel) { int irow = UNSHIFT_INDEX(hrowi[iel]); int iput = hinrow[irow]; int kput = mrstrt[irow]; int nextRow=eta_next[irow]; assert (kput>0); kput += iput; if (kput < mrstrt[nextRow]) { hinrow[irow] = iput + 1; hcoli[kput] = kpivrw; de2val[kput] = dluval[iel]; } else { /* no room - switch off */ doSparse=0; /* possible kpivrw 1 */ k1 = mrstrt[kpivrw]; mrstrt[1]=-1; fact->rows_ok = false; goto L1226; } } } else { for (iel = i1; iel <= i2; ++iel) { int j,k; int irow = UNSHIFT_INDEX(hrowi[iel]); int iput = hinrow[irow]; k=mrstrt[irow]+iput; j=eta_next[irow]; if (k >= mrstrt[j]) { /* no room - can we make some? */ int klast=eta_last[nrow+1]; int jput=mrstrt[klast]+hinrow[klast]+2; int distance=mrstrt[nrow+1]-jput; if (iput+1nnetas-fact->nnentu-fact->nnentl-3); if (spare>nrow<<1) { /* presumbly, this compacts the rows */ int jrow,jput; if (1) { if (fact->num_resets<1000000) { int etasize =CoinMax(4*fact->nnentu+ (fact->nnetas-fact->nnentl)+1000,fact->eta_size); if (ifrows) { fact->num_resets++; if (npivot>40&&fact->num_resets<<4>npivot) { fact->eta_size=static_cast(1.05*fact->eta_size); fact->num_resets=1000000; } } else { fact->eta_size=static_cast(1.1*fact->eta_size); fact->num_resets=1000000; } fact->eta_size=CoinMin(fact->eta_size,etasize); if (fact->maxNNetas>0&&fact->eta_size> fact->maxNNetas) { fact->eta_size=fact->maxNNetas; } } } jrow=eta_next[0]; jput=1; for (j=0;jnrow<<3) { spare=3; } else if (spare>nrow<<2) { spare=1; } else { spare=0; } jput+=nrow*spare;; jrow=eta_last[nrow+1]; for (j=0;jrows_ok = false; goto L1226; } } } /* now we have room - append the new value */ hinrow[irow] = iput + 1; hcoli[k] = kpivrw; de2val[k] = dluval[iel]; } } } /* TAKE OUT ALL ELEMENTS IN PIVOT ROW */ k1 = mrstrt[kpivrw]; L1226: { int k2 = k1 + hinrow[kpivrw] - 1; /* "delete" the row */ hinrow[kpivrw] = 0; j = 0; if (doSparse) { /* remove pivot row entries from the corresponding columns */ for (k = k1; k <= k2; ++k) { int icol = hcoli[k]; int kx = mcstrt[icol]; int nel = hrowi[kx]; for (iel = kx + 1; iel <= kx+nel; iel ++) { if (hrowi[iel] == jpivrw) { break; } } if (iel <= kx+nel) { /* this has to happen, right?? */ /* copy the element into a temporary */ dwork1[icol] = dluval[iel]; mpt2[nincol++]=icol; /*nonzero[icol-1]=1;*/ hrowi[kx]=nel-1; /* column is shorter by one */ j=1; hrowi[iel]=hrowi[kx+nel]; dluval[iel]=dluval[kx+nel]; #ifdef CLP_REUSE_ETAS hrowi[kx+nel]=jpivrw; dluval[kx+nel]=dwork1[icol]; #endif } } if (j != 0) { /* now compute r', the new R transform */ orig_nincol=c_ekkbtju_sparse(fact, dwork1, mpt2, nincol, spare); dwork1[kpivrw]=0.0; } } else { /* row version isn't ok (?) */ for (k = k1; k <= k2; ++k) { int icol = hcoli[k]; int kx = mcstrt[icol]; int nel = hrowi[kx]; j = kx+nel; int iel; for (iel=kx+1;iel<=j;iel++) { if (hrowi[iel]==jpivrw) break; } dwork1[icol] = dluval[iel]; if (kxlast_dense_mcstrt) { hrowi[kx] = nel - 1; /* shorten column */ /* not packing - presumably column isn't sorted */ hrowi[iel] = hrowi[j]; dluval[iel] = dluval[j]; #ifdef CLP_REUSE_ETAS hrowi[j]=jpivrw; dluval[j]=dwork1[icol]; #endif } else { /* dense element - just zero it */ dluval[iel]=0.0; } } if (j != 0) { /* Find first nonzero */ int ipiv = hpivco_new[kpivrw]; while(ipiv<=nrow) { if (!dwork1[ipiv]) { ipiv=hpivco_new[ipiv]; } else { break; } } if (ipiv<=nrow) { /* DO U */ /* now compute r', the new R transform */ c_ekkbtju(fact, dwork1, ipiv); } } } } } if (kpivrw==fact->first_dense) { /* increase until valid pivot */ fact->first_dense=hpivco_new[fact->first_dense]; } else if (kpivrw==fact->last_dense) { fact->last_dense=back[fact->last_dense]; } if (fact->first_dense==fact->last_dense) { fact->ndenuc=0; fact->first_dense=0; fact->last_dense=-1; } if (! (ifRowCopy && j==0)) { /* increase amount of work on Etas */ /* **************************************************************** */ /* DO ROW ETAS IN L */ { if (!doSparse) { dwork1[kpivrw] = 0.; #if 0 orig_nincol=c_ekksczr(fact,nrow, dwork1, mpt2); del3=c_ekkputl(fact, mpt2, dwork1, del3, orig_nincol, nuspik); #else orig_nincol=c_ekkputl2(fact, dwork1, &del3, nuspik); #endif } else { del3=c_ekkputl(fact, mpt2, dwork1, del3, orig_nincol, nuspik); } } if (orig_nincol != 0) { /* STORE AS A ROW VECTOR */ int n = fact->nR_etas+1; int i1 = fact->R_etas_start[n]; fact->nR_etas=n; fact->R_etas_start[n + 1] = i1 - orig_nincol; hpivco[fact->nR_etas + nrow+3] = kpivrw; } } /* CHECK DEL3 AGAINST DALPHA/DOUT */ { int kx = mcstrt[kpivrw]; double dout = dluval[kx]; double dcheck = fabs(dalpha / dout); double difference=0.0; if (fabs(del3) > CoinMin(1.0e-8,fact->drtpiv*0.99999)) { double checkTolerance; if ( fact->npivots < 2 ) { checkTolerance = 1.0e-5; } else if ( fact->npivots < 10 ) { checkTolerance = 1.0e-6; } else if ( fact->npivots < 50 ) { checkTolerance = 1.0e-8; } else { checkTolerance = 1.0e-9; } difference = fabs(1.0-fabs(del3)/dcheck); if (difference > 0.1*checkTolerance) { if (difference < checkTolerance|| (difference<1.0e-7&&fact->npivots>=50)) { irtcod=1; #ifdef PRINT_DEBUG printf("mildly bad %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n", difference,fact->npivots,del3,dcheck,dalpha); #endif } else { irtcod=2; #ifdef PRINT_DEBUG printf("bad %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n", difference,fact->npivots,del3,dcheck,dalpha); #endif } } } else { irtcod=2; #ifdef PRINT_DEBUG printf("bad small %g after %d pivots, etsj %g ftncheck %g ftnalpha %g\n", difference,fact->npivots,del3,dcheck,dalpha); #endif } if (irtcod>1) goto L8000; fact->npivots++; } mcstrt[kpivrw] = fact->nnentu; #ifdef CLP_REUSE_ETAS { int * putSeq = fact->xrsadr+2*fact->nrowmx+2; int * position = putSeq+fact->maxinv; int * putStart = position+fact->maxinv; putStart[fact->nrow+fact->npivots-1]=fact->nnentu; } #endif dluval[fact->nnentu] = 1. / del3; /* new pivot */ hrowi[fact->nnentu] = nuspik; /* new nelems */ #ifndef NDEBUG { int lastSlack = fact->lastSlack; int firstDo=hpivco_new[lastSlack]; int ipiv=hpivco_new[0]; int now = fact->numberSlacks; if (now) { while (1) { if (ipiv>fact->nrow||ipiv==firstDo) break; assert (c_ekk_IsSet(fact->bitArray,ipiv)); ipiv=hpivco_new[ipiv]; } if (ipiv<=fact->nrow) { while (1) { if (ipiv>fact->nrow) break; assert (!c_ekk_IsSet(fact->bitArray,ipiv)); ipiv=hpivco_new[ipiv]; } } } } #endif { /* do new hpivco */ int inext=hpivco_new[kpivrw]; int iback=back[kpivrw]; if (inext!=nrow+1) { int ilast=back[nrow+1]; hpivco_new[iback]=inext; back[inext]=iback; assert (hpivco_new[ilast]==nrow+1); hpivco_new[ilast]=kpivrw; back[kpivrw]=ilast; hpivco_new[kpivrw]=nrow+1; back[nrow+1]=kpivrw; } } { int lastSlack = fact->lastSlack; int now = fact->numberSlacks; if (now&&mcstrt_piv<=mcstrt[lastSlack]) { if (c_ekk_IsSet(fact->bitArray,kpivrw)) { /*printf("piv %d lastSlack %d\n",mcstrt_piv,lastSlack);*/ fact->numberSlacks--; now--; /* one less slack */ c_ekk_Unset(fact->bitArray,kpivrw); if (now&&kpivrw==lastSlack) { int i; int ipiv; ipiv=hpivco_new[0]; for (i=0;ibitArray,ipiv)); assert (!c_ekk_IsSet(fact->bitArray,hpivco_new[ipiv])||hpivco_new[ipiv]>fact->nrow); fact->lastSlack = lastSlack; } else if (!now) { fact->lastSlack=0; } } } fact->firstNonSlack=hpivco_new[lastSlack]; #ifndef NDEBUG { int lastSlack = fact->lastSlack; int firstDo=hpivco_new[lastSlack]; int ipiv=hpivco_new[0]; int now = fact->numberSlacks; if (now) { while (1) { if (ipiv>fact->nrow||ipiv==firstDo) break; assert (c_ekk_IsSet(fact->bitArray,ipiv)); ipiv=hpivco_new[ipiv]; } if (ipiv<=fact->nrow) { while (1) { if (ipiv>fact->nrow) break; assert (!c_ekk_IsSet(fact->bitArray,ipiv)); ipiv=hpivco_new[ipiv]; } } } } #endif } fact->nnentu += nuspik; #ifdef CLP_REUSE_ETAS if (fact->first_dense>=fact->last_dense) { // save fact->nnentu++; dluval[fact->nnentu]=del3Orig; hrowi[fact->nnentu]=kpivrw; int * putSeq = fact->xrsadr+2*fact->nrowmx+2; int * position = putSeq+fact->maxinv; int * putStart = position+fact->maxinv; int nnentu_at_factor=putStart[fact->nrow]&0x7fffffff; //putStart[fact->nrow+fact->npivots]=fact->nnentu+1; int where; if (mcstrt_pivnrow; for (where=fact->npivots-1;where>=0;where--) { if (mcstrt_piv==(look[where]&0x7fffffff)) break; } assert (where>=0); where += fact->nrow; } position[fact->npivots-1]=where; if (orig_nincol == 0) { // flag putStart[fact->nrow+fact->npivots-1] |= 0x80000000; } } #endif { int kdnspt = fact->nnetas - fact->nnentl; /* fact->R_etas_start[fact->nR_etas + 1] is -(the number of els in R) */ nnentl = fact->nnetas - ((kdnspt - 1) + fact->R_etas_start[fact->nR_etas + 1]); } fact->demark = (fact->nnentu + nnentl) - fact->demark; /* if need to redo row version */ if (! fact->rows_ok&&fact->first_dense>=fact->last_dense) { int extraSpace=10000; int spareSpace; if (fact->if_sparse_update>0) { spareSpace=(fact->nnetas-fact->nnentu-fact->nnentl); } else { /* missing out nnentl stuff */ spareSpace=fact->nnetas-fact->nnentu; } /* save clean row copy if enough room */ nroom = spareSpace / nrow; if ((fact->nnentu<<3)>150*fact->maxinv) { extraSpace=150*fact->maxinv; } else { extraSpace=fact->nnentu<<3; } ifrows = false; if (fact->nnetas>fact->nnentu+fact->nnentl+extraSpace) { ifrows = true; } if (nroom < 5) { ifrows = false; } if (nroom > CoinMin(50, fact->maxinv - (fact->iterno - fact->iterin))) { ifrows = true; } #ifdef PRINT_DEBUGx printf(" redoing row copy %d %d %d\n",ifrows,nroom,spareSpace); #endif if (1) { if (fact->num_resets<1000000) { if (ifrows) { fact->num_resets++; if (npivot>40&&fact->num_resets<<4>npivot) { fact->eta_size=static_cast(1.05*fact->eta_size); fact->num_resets=1000000; } } else { fact->eta_size=static_cast(1.1*fact->eta_size); fact->num_resets=1000000; } if (fact->maxNNetas>0&&fact->eta_size> fact->maxNNetas) { fact->eta_size=fact->maxNNetas; } } } fact->rows_ok = ifrows; if (ifrows) { int ibase = 1; c_ekkizero(nrow,&hinrow[1]); for (i = 1; i <= nrow; ++i) { int kx = mcstrt[i]; int nel = hrowi[kx]; int kcs = kx + 1; int kce = kx + nel; for (kc = kcs; kc <= kce; ++kc) { int irow = UNSHIFT_INDEX(hrowi[kc]); if (dluval[kc]) { hinrow[irow]++; } } } int * eta_last=mpermu+nrow*2+3; int * eta_next=eta_last+nrow+2; eta_next[0]=1; for (i = 1; i <= nrow; ++i) { eta_next[i]=i+1; eta_last[i]=i-1; mrstrt[i] = ibase; ibase = ibase + hinrow[i] + nroom; hinrow[i] = 0; } eta_last[nrow+1]=nrow; //eta_next[nrow+1]=nrow+2; mrstrt[nrow+1]=ibase; if (fact->xe2adr == 0) { for (i = 1; i <= nrow; ++i) { int kx = mcstrt[i]; int nel = hrowi[kx]; int kcs = kx + 1; int kce = kx + nel; for (kc = kcs; kc <= kce; ++kc) { if (dluval[kc]) { int irow = UNSHIFT_INDEX(hrowi[kc]); int iput = hinrow[irow]; assert (irow); hcoli[mrstrt[irow] + iput] = i; hinrow[irow] = iput + 1; } } } } else { for (i = 1; i <= nrow; ++i) { int kx = mcstrt[i]; int nel = hrowi[kx]; int kcs = kx + 1; int kce = kx + nel; for (kc = kcs; kc <= kce; ++kc) { int irow = UNSHIFT_INDEX(hrowi[kc]); int iput = hinrow[irow]; hcoli[mrstrt[irow] + iput] = i; de2val[mrstrt[irow] + iput] = dluval[kc]; hinrow[irow] = iput + 1; } } } } else { mrstrt[1] = 0; if (fact->if_sparse_update>0&&fact->iterno-fact->iterin>100) { goto L7000; } } } goto L8000; /* OUT OF SPACE - COULD PACK DOWN */ L7000: irtcod = 1; #ifdef PRINT_DEBUG printf(" out of space\n"); #endif if (1) { if ((npivot<<3)nbfinv) { /* low on space */ if (npivot<10) { fact->eta_size=fact->eta_size<<1; } else { double ratio=fact->nbfinv; double ratio2=npivot<<3; ratio=ratio/ratio2; if (ratio>2.0) { ratio=2.0; } /* endif */ fact->eta_size=static_cast(ratio*fact->eta_size); } /* endif */ } else { fact->eta_size=static_cast(1.05*fact->eta_size); } /* endif */ if (fact->maxNNetas>0&&fact->eta_size> fact->maxNNetas) { fact->eta_size=fact->maxNNetas; } } /* ================= IF ERROR SHOULD WE GET RID OF LAST ITERATION??? */ L8000: *nuspikp = nuspik; #ifdef MORE_DEBUG for (int i=1;i<=fact->nrow;i++) { int kx=mcstrt[i]; int nel=hrowi[kx]; for (int j=0;jsave_nnentu=fact->nnentu; #endif return (irtcod); } /* c_ekketsj */ static void c_ekkftj4p(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int firstNonZero) { /* this is where the L factors start, because this is the place * where c_ekktria starts laying them down (see initialization of xnetal). */ int lstart=fact->lstart; const int * COIN_RESTRICT hpivco = fact->kcpadr; int firstLRow = hpivco[lstart]; if (firstNonZero>firstLRow) { lstart += firstNonZero-firstLRow; } assert (firstLRow==fact->firstLRow); int jpiv=hpivco[lstart]; const double * COIN_RESTRICT dluval = fact->xeeadr; const int * COIN_RESTRICT hrowi = fact->xeradr; const int * COIN_RESTRICT mcstrt = fact->xcsadr+lstart; int ndo=fact->xnetal-lstart; int i, iel; /* find first non-zero */ for (i=0;i kce1; --iel) { int irow0 = hrowi[iel]; SHIFT_REF(dwork1, irow0) += dv * dluval[iel]; } } } } /* c_ekkftj4p */ /* * This version is more efficient for input columns that are sparse. * It is instructive to consider the case of an especially sparse column, * which is a slack. The slack for row r has exactly one non-zero element, * in row r, which is +-1.0. Let pr = mpermu[r]. * In this case, nincol==1 and mpt[0] == pr on entry. * if mpt[0] == pr <= jpiv * then this slack is completely unaffected by L; * this is reflected by the fact that save_where = last * after the first loop, so none of the remaining loops * ever execute, * else if mpt[0] == pr > jpiv, but pr-jpiv > ndo * then the slack is also unaffected by L, this time because * its row is "after" L. During factorization, it may * be the case that the first part of the basis is upper * triangular (c_ekktria), but it may also be the case that the * last part of the basis is upper triangular (in which case the * L triangle gets "chopped off" on the right). In both cases, * no L entries are required. Since in this case the tests * (i<=ndo) will fail (and dwork1[ipiv]==1.0), the code will * do nothing. * else if mpt[0] == pr > jpiv and pr-jpiv <= ndo * then the slack *is* affected by L. * the for-loop inside the second while-loop will discover * that none of the factors for the corresponding column of L * are non-zero in the slack column, so last will not be incremented. * We multiply the eta-vector, and the last loop does nothing. */ static int c_ekkftj4_sparse(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int nincol,int * COIN_RESTRICT spare) { const int nrow = fact->nrow; /* this is where the L factors start, because this is the place * where c_ekktria starts laying them down (see initialization of xnetal). */ int lstart=fact->lstart; const int * COIN_RESTRICT hpivco = fact->kcpadr; const double * COIN_RESTRICT dluval = fact->xeeadr; const int * COIN_RESTRICT hrowi = fact->xeradr; const int * COIN_RESTRICT mcstrt = fact->xcsadr+lstart-1; double tolerance = fact->zeroTolerance; int jpiv=hpivco[lstart]-1; char * COIN_RESTRICT nonzero=fact->nonzero; int ndo=fact->xnetalval; int k,nStack; int nList=0; int iPivot; int * COIN_RESTRICT list = spare; int * COIN_RESTRICT stack = spare+nrow; int * COIN_RESTRICT next = stack+nrow; double dv; int iel; int nput=0,kput=nrow; int check=jpiv+ndo+1; const int * COIN_RESTRICT mcstrt2 = mcstrt-jpiv; for (k=0;kjpiv&&iPivotjpiv&&kPivotmcstrt2[kPivot]) { /* finished so mark */ list[nList++]=kPivot; nonzero[kPivot]=1; } else { kPivot=UNSHIFT_INDEX(hrowi[j]); /* put back on stack */ next[nStack++] ++; if (!nonzero[kPivot]) { /* and new one */ stack[nStack]=kPivot; nonzero[kPivot]=2; next[nStack++]=mcstrt2[kPivot+1]+1; } } } else if (kPivot>=check) { list[--kput]=kPivot; nonzero[kPivot]=1; } } } else if (nonzero[iPivot]!=1) { /* nothing to do (except check size at end) */ list[--kput]=iPivot; nonzero[iPivot]=1; } } for (k=nList-1;k>=0;k--) { double dv; iPivot = list[k]; dv = dwork1[iPivot]; nonzero[iPivot]=0; if (fabs(dv) > tolerance) { /* the same code as in c_ekkftj4p */ int kce1 = mcstrt2[iPivot + 1]; for (iel = mcstrt2[iPivot]; iel > kce1; --iel) { int irow0 = hrowi[iel]; SHIFT_REF(dwork1, irow0) += dv * dluval[iel]; } mpt[nput++]=iPivot; } else { dwork1[iPivot]=0.0; /* force to zero, not just near zero */ } } /* check remainder */ for (k=kput;k tolerance) { mpt[nput++]=iPivot; } else { dwork1[iPivot]=0.0; /* force to zero, not just near zero */ } } return (nput); } /* c_ekkftj4 */ /* * This applies the R transformations of the F-T LU update procedure, * equation 3.11 on p. 270 in the 1972 Math Programming paper. * Note that since the non-zero off-diagonal elements are in a row, * multiplying an R by a column is a reduction, not like applying * L or U. * * Note that this may introduce new non-zeros in dwork1, * since an hpivco entry may correspond to a zero element, * and that some non-zeros in dwork1 may be cancelled. */ static int c_ekkftjl_sparse3(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int * COIN_RESTRICT hput, double * COIN_RESTRICT dluput , int nincol) { int i; int knext; int ipiv; double dv; const double * COIN_RESTRICT dluval = fact->R_etas_element+1; const int * COIN_RESTRICT hrowi = fact->R_etas_index+1; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; int ndo=fact->nR_etas; double tolerance = fact->zeroTolerance; const int * COIN_RESTRICT hpivco = fact->hpivcoR; /* and make cleaner */ hput++; dluput++; /* DO ANY ROW TRANSFORMATIONS */ /* Function Body */ /* mpt has correct list of nonzeros */ if (ndo != 0) { knext = mcstrt[1]; for (i = 1; i <= ndo; ++i) { int k1 = knext; /* == mcstrt[i] */ int iel; ipiv = hpivco[i]; dv = dwork1[ipiv]; bool onList = (dv!=0.0); knext = mcstrt[i + 1]; for (iel = knext ; iel < k1; ++iel) { int irow = hrowi[iel]; dv += SHIFT_REF(dwork1, irow) * dluval[iel]; } /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero. * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero. */ if (onList) { if (fabs(dv) > tolerance) { dwork1[ipiv]=dv; } else { dwork1[ipiv] = 1.0e-128; } } else { if (fabs(dv) > tolerance) { /* put on list if not there */ mpt[nincol++]=ipiv; dwork1[ipiv]=dv; } } } } knext=0; for (i=0; i tolerance) { hput[knext]=SHIFT_INDEX(ipiv); dluput[knext]=dv; mpt[knext++]=ipiv; } else { dwork1[ipiv]=0.0; } } return knext; } /* c_ekkftjl */ static int c_ekkftjl_sparse2(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int * COIN_RESTRICT mpt, int nincol) { double tolerance = fact->zeroTolerance; const double * COIN_RESTRICT dluval = fact->R_etas_element+1; const int * COIN_RESTRICT hrowi = fact->R_etas_index+1; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; int ndo=fact->nR_etas; const int * COIN_RESTRICT hpivco = fact->hpivcoR; int i; int knext; int ipiv; double dv; /* DO ANY ROW TRANSFORMATIONS */ /* Function Body */ /* mpt has correct list of nonzeros */ if (ndo != 0) { knext = mcstrt[1]; for (i = 1; i <= ndo; ++i) { int k1 = knext; /* == mcstrt[i] */ int iel; ipiv = hpivco[i]; dv = dwork1[ipiv]; bool onList = (dv!=0.0); knext = mcstrt[i + 1]; for (iel = knext ; iel < k1; ++iel) { int irow = hrowi[iel]; dv += SHIFT_REF(dwork1, irow) * dluval[iel]; } /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero. * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero. */ if (onList) { if (fabs(dv) > tolerance) { dwork1[ipiv]=dv; } else { dwork1[ipiv] = 1.0e-128; } } else { if (fabs(dv) > tolerance) { /* put on list if not there */ mpt[nincol++]=ipiv; dwork1[ipiv]=dv; } } } } knext=0; for (i=0; i tolerance) { mpt[knext++]=ipiv; } else { dwork1[ipiv]=0.0; } } return knext; } /* c_ekkftjl */ static void c_ekkftjl(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1) { double tolerance = fact->zeroTolerance; const double * COIN_RESTRICT dluval = fact->R_etas_element+1; const int * COIN_RESTRICT hrowi = fact->R_etas_index+1; const int * COIN_RESTRICT mcstrt = fact->R_etas_start; int ndo=fact->nR_etas; const int * COIN_RESTRICT hpivco = fact->hpivcoR; int i; int knext; /* DO ANY ROW TRANSFORMATIONS */ /* Function Body */ if (ndo != 0) { /* * The following three lines are here just to ensure that this * new formulation of the loop has exactly the same effect * as the original. */ { int ipiv = hpivco[1]; double dv = dwork1[ipiv]; dwork1[ipiv] = (fabs(dv) > tolerance) ? dv : 0.0; } knext = mcstrt[1]; for (i = 1; i <= ndo; ++i) { int k1 = knext; /* == mcstrt[i] */ int ipiv = hpivco[i]; double dv = dwork1[ipiv]; int iel; //#define UNROLL3 2 #ifndef UNROLL3 #if CLP_OSL==2||CLP_OSL==3 #define UNROLL3 2 #else #define UNROLL3 1 #endif #endif knext = mcstrt[i + 1]; #if UNROLL3<2 for (iel = knext ; iel < k1; ++iel) { int irow = hrowi[iel]; dv += SHIFT_REF(dwork1, irow) * dluval[iel]; } #else iel = knext; if (((k1-knext)&1)!=0) { int irow = hrowi[iel]; dv += SHIFT_REF(dwork1, irow) * dluval[iel]; iel++; } for ( ; iel < k1; iel+=2) { int irow0 = hrowi[iel]; double dval0 = dluval[iel]; int irow1 = hrowi[iel+1]; double dval1 = dluval[iel+1]; dv += SHIFT_REF(dwork1, irow0) * dval0; dv += SHIFT_REF(dwork1, irow1) * dval1; } #endif /* (1) if dwork[ipiv] == 0.0, then this may add a non-zero. * (2) if dwork[ipiv] != 0.0, then this may cancel out a non-zero. */ dwork1[ipiv] = (fabs(dv) > tolerance) ? dv : 0.0; } } } /* c_ekkftjl */ /* this assumes it is ok to reference back[loop_limit] */ /* another 3 seconds from a ~570 second run can be trimmed * by using two routines, one with scan==true and the other false, * since that eliminates the branch instructions involving them * entirely. This was how the code was originally written. * However, I'm still hoping that eventually we can use * C++ templates to do that for us automatically. */ static void c_ekkftjup_scan_aux(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko , int loop_limit, int *ip, int ** mptp) { const double * COIN_RESTRICT dluval = fact->xeeadr+1; const int * COIN_RESTRICT hrowi = fact->xeradr+1; const int * COIN_RESTRICT mcstrt = fact->xcsadr; const int * COIN_RESTRICT hpivro = fact->krpadr; const int * COIN_RESTRICT back=fact->back; double tolerance = fact->zeroTolerance; int ipiv = *ip; double dv = dwork1[ipiv]; int * mptX = *mptp; assert (mptX); while (ipiv != loop_limit) { int next_ipiv = back[ipiv]; dwork1[ipiv] = 0.0; #ifndef UNROLL4 #define UNROLL4 2 #endif /* invariant: dv == dwork1[ipiv] */ /* in the case of world.mps with dual, this condition is true * only 20-60% of the time. */ if (fabs(dv) > tolerance) { const int kx = mcstrt[ipiv]; const int nel = hrowi[kx-1]; const double dpiv = dluval[kx-1]; #if UNROLL4>1 const int * hrowi2=hrowi+kx; const int * hrowi2end=hrowi2+nel; const double * dluval2=dluval+kx; #else int iel; #endif dv*=dpiv; /* * The following loop is the unrolled version of this: * * for (iel = kx+1; iel <= kx + nel; iel++) { * SHIFT_REF(dwork1, hrowi[iel]) -= dv * dluval[iel]; * } */ #if UNROLL4<2 iel = kx; if (nel&1) { int irow = hrowi[iel]; double dval=dluval[iel]; SHIFT_REF(dwork1, irow) -= dv*dval; iel++; } for (; iel < kx + nel; iel+=2) { int irow0 = hrowi[iel]; int irow1 = hrowi[iel+1]; double dval0=dluval[iel]; double dval1=dluval[iel+1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); d0-=dv*dval0; d1-=dv*dval1; SHIFT_REF(dwork1, irow0)=d0; SHIFT_REF(dwork1, irow1)=d1; } /* end loop */ #else if ((nel&1)!=0) { int irow = *hrowi2; double dval=*dluval2; SHIFT_REF(dwork1, irow) -= dv*dval; hrowi2++; dluval2++; } for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) { int irow0 = hrowi2[0]; int irow1 = hrowi2[1]; double dval0=dluval2[0]; double dval1=dluval2[1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); d0-=dv*dval0; d1-=dv*dval1; SHIFT_REF(dwork1, irow0)=d0; SHIFT_REF(dwork1, irow1)=d1; } #endif /* put this down here so that dv is less likely to cause a stall */ if (fabs(dv) >= tolerance) { int iput=hpivro[ipiv]; dworko[iput]=dv; *mptX++=iput-1; } } dv = dwork1[next_ipiv]; ipiv=next_ipiv; } /* endwhile */ *mptp = mptX; *ip = ipiv; } static void c_ekkftjup_aux3(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko, const int * COIN_RESTRICT back, const int * COIN_RESTRICT hpivro, int *ipivp, int loop_limit, int **mptXp) { double tolerance = fact->zeroTolerance; int ipiv = *ipivp; if (ipiv!=loop_limit) { int *mptX = *mptXp; double dv = dwork1[ipiv]; do { int next_ipiv = back[ipiv]; double next_dv=dwork1[next_ipiv]; dwork1[ipiv]=0.0; if (fabs(dv)>=tolerance) { int iput=hpivro[ipiv]; dworko[iput]=dv; *mptX++=iput-1; } ipiv = next_ipiv; dv = next_dv; } while (ipiv!=loop_limit); *mptXp = mptX; *ipivp = ipiv; } } static void c_ekkftju_dense(const double *dluval, const int * COIN_RESTRICT hrowi, const int * COIN_RESTRICT mcstrt, const int * COIN_RESTRICT back, double * COIN_RESTRICT dwork1, int * start, int last, int offset , double *densew) { int ipiv=*start; while (ipiv>last ) { const int ipiv1=ipiv; double dv1=dwork1[ipiv1]; ipiv=back[ipiv]; if (fabs(dv1) > 1.0e-14) { const int kx1 = mcstrt[ipiv1]; const int nel1 = hrowi[kx1-1]; const double dpiv1 = dluval[kx1-1]; int iel,k; const int n1=offset+ipiv1; /* number in dense part */ const int nsparse1=nel1-n1; const int k1=kx1+nsparse1; const double *dlu1=&dluval[k1]; int ipiv2=back[ipiv1]; const int nskip=ipiv1-ipiv2; dv1*=dpiv1; dwork1[ipiv1]=dv1; for (k = n1 - (nskip-1) -1; k >=0 ; k--) { const double dval = dv1*dlu1[k]; double dv2=densew[k]-dval; ipiv=back[ipiv]; if (fabs(dv2) > 1.0e-14) { const int kx2 = mcstrt[ipiv2]; const int nel2 = hrowi[kx2-1]; const double dpiv2 = dluval[kx2-1]; /* number in dense part is k */ const int nsparse2=nel2-k; const int k2=kx2+nsparse2; const double *dlu2=&dluval[k2]; dv2*=dpiv2; densew[k]=dv2; /* was dwork1[ipiv2]=dv2; */ k--; /* * The following loop is the unrolled version of: * * for (; k >= 0; k--) { * densew[k]-=dv1*dlu1[k]+dv2*dlu2[k]; * } */ if ((k&1)==0) { densew[k]-=dv1*dlu1[k]+dv2*dlu2[k]; k--; } for (; k >=0 ; k-=2) { double da,db; da=densew[k]; db=densew[k-1]; da-=dv1*dlu1[k]; db-=dv1*dlu1[k-1]; da-=dv2*dlu2[k]; db-=dv2*dlu2[k-1]; densew[k]=da; densew[k-1]=db; } /* end loop */ /* * The following loop is the unrolled version of: * * for (iel=kx2+nsparse2-1; iel >= kx2; iel--) { * SHIFT_REF(dwork1, hrowi[iel]) -= dv2*dluval[iel]; * } */ iel=kx2+nsparse2-1; if ((nsparse2&1)!=0) { int irow0 = hrowi[iel]; double dval=dluval[iel]; SHIFT_REF(dwork1,irow0) -= dv2*dval; iel--; } for (; iel >=kx2 ; iel-=2) { double dval0 = dluval[iel]; double dval1 = dluval[iel-1]; int irow0 = hrowi[iel]; int irow1 = hrowi[iel-1]; double d0 = SHIFT_REF(dwork1, irow0); double d1 = SHIFT_REF(dwork1, irow1); d0-=dv2*dval0; d1-=dv2*dval1; SHIFT_REF(dwork1, irow0) = d0; SHIFT_REF(dwork1, irow1) = d1; } /* end loop */ } else { densew[k]=0.0; /* skip if next deleted */ k-=ipiv2-ipiv-1; ipiv2=ipiv; if (ipiv=0 ; k--) { double dval; dval=dv1*dlu1[k]; densew[k]=densew[k]-dval; } } } } /* * The following loop is the unrolled version of: * * for (iel=kx1+nsparse1-1; iel >= kx1; iel--) { * SHIFT_REF(dwork1, hrowi[iel]) -= dv1*dluval[iel]; * } */ iel=kx1+nsparse1-1; if ((nsparse1&1)!=0) { int irow0 = hrowi[iel]; double dval=dluval[iel]; SHIFT_REF(dwork1, irow0) -= dv1*dval; iel--; } for (; iel >=kx1 ; iel-=2) { double dval0=dluval[iel]; double dval1=dluval[iel-1]; int irow0 = hrowi[iel]; int irow1 = hrowi[iel-1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); d0-=dv1*dval0; d1-=dv1*dval1; SHIFT_REF(dwork1, irow0) = d0; SHIFT_REF(dwork1, irow1) = d1; } /* end loop */ } else { dwork1[ipiv1]=0.0; } /* endif */ } /* endwhile */ *start=ipiv; } /* do not use return value if mpt==0 */ /* using dual, this is usually called via c_ekkftrn_ft, from c_ekksdul * (so mpt is non-null). * it is generally called every iteration, but sometimes several iterations * are skipped (null moves?). * * generally, back[i] == i-1 (initialized in c_ekkshfv towards the end). */ static int c_ekkftjup(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int last, double * COIN_RESTRICT dworko , int * COIN_RESTRICT mpt) { const double * COIN_RESTRICT dluval = fact->xeeadr; const int * COIN_RESTRICT hrowi = fact->xeradr; const int * COIN_RESTRICT mcstrt = fact->xcsadr; const int * COIN_RESTRICT hpivro = fact->krpadr; double tolerance = fact->zeroTolerance; int ndenuc=fact->ndenuc; const int first_dense=fact->first_dense; const int last_dense=fact->last_dense; int i; int * mptX = mpt; const int nrow = fact->nrow; const int * COIN_RESTRICT back=fact->back; int ipiv=back[nrow+1]; if (last_dense>first_dense&&mcstrt[ipiv]>=mcstrt[last_dense]) { c_ekkftjup_scan_aux(fact, dwork1, dworko, last_dense, &ipiv, &mptX); { int j; int n=0; const int firstDense = nrow- ndenuc+1; double *densew = &dwork1[firstDense]; int offset; /* check first dense to see where in triangle it is */ int last=first_dense; const int k1=mcstrt[last]; const int k2=k1+hrowi[k1]; for (j=k2; j>k1; j--) { int irow = UNSHIFT_INDEX(hrowi[j]); if (irow=tolerance) { int iput=hpivro[ipiv]; dworko[iput]=-dv; *mptX++=iput-1; } ipiv = next_ipiv; dv = next_dv; } while (ipiv!=0); } return static_cast(mptX-mpt); } /* this assumes it is ok to reference back[loop_limit] */ /* another 3 seconds from a ~570 second run can be trimmed * by using two routines, one with scan==true and the other false, * since that eliminates the branch instructions involving them * entirely. This was how the code was originally written. * However, I'm still hoping that eventually we can use * C++ templates to do that for us automatically. */ static void c_ekkftjup_scan_aux_pack(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko , int loop_limit, int *ip, int ** mptp) { double tolerance = fact->zeroTolerance; const double *dluval = fact->xeeadr+1; const int *hrowi = fact->xeradr+1; const int *mcstrt = fact->xcsadr; const int *hpivro = fact->krpadr; const int * back=fact->back; int ipiv = *ip; double dv = dwork1[ipiv]; int * mptX = *mptp; #if 0 int inSlacks=0; int lastSlack; if (fact->numberSlacks!=0) lastSlack=fact->lastSlack; else lastSlack=0; if (c_ekk_IsSet(fact->bitArray,ipiv)) { printf("already in slacks - ipiv %d\n",ipiv); inSlacks=1; return; } #endif assert (mptX); while (ipiv != loop_limit) { int next_ipiv = back[ipiv]; #if 0 if (ipiv==lastSlack) { printf("now in slacks - ipiv %d\n",ipiv); inSlacks=1; break; } if (inSlacks) { assert (c_ekk_IsSet(fact->bitArray,ipiv)); assert (dluval[mcstrt[ipiv]-1]==-1.0); assert (hrowi[mcstrt[ipiv]-1]==0); } #endif dwork1[ipiv] = 0.0; /* invariant: dv == dwork1[ipiv] */ /* in the case of world.mps with dual, this condition is true * only 20-60% of the time. */ if (fabs(dv) > tolerance) { const int kx = mcstrt[ipiv]; const int nel = hrowi[kx-1]; const double dpiv = dluval[kx-1]; #ifndef UNROLL5 #define UNROLL5 2 #endif #if UNROLL5>1 const int * hrowi2=hrowi+kx; const int * hrowi2end=hrowi2+nel; const double * dluval2=dluval+kx; #else int iel; #endif dv*=dpiv; /* * The following loop is the unrolled version of this: * * for (iel = kx+1; iel <= kx + nel; iel++) { * SHIFT_REF(dwork1, hrowi[iel]) -= dv * dluval[iel]; * } */ #if UNROLL5<2 iel = kx; if (nel&1) { int irow = hrowi[iel]; double dval=dluval[iel]; SHIFT_REF(dwork1, irow) -= dv*dval; iel++; } for (; iel < kx + nel; iel+=2) { int irow0 = hrowi[iel]; int irow1 = hrowi[iel+1]; double dval0=dluval[iel]; double dval1=dluval[iel+1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); d0-=dv*dval0; d1-=dv*dval1; SHIFT_REF(dwork1, irow0)=d0; SHIFT_REF(dwork1, irow1)=d1; } /* end loop */ #else if ((nel&1)!=0) { int irow = *hrowi2; double dval=*dluval2; SHIFT_REF(dwork1, irow) -= dv*dval; hrowi2++; dluval2++; } for (; hrowi2 < hrowi2end; hrowi2 +=2,dluval2 +=2) { int irow0 = hrowi2[0]; int irow1 = hrowi2[1]; double dval0=dluval2[0]; double dval1=dluval2[1]; double d0=SHIFT_REF(dwork1, irow0); double d1=SHIFT_REF(dwork1, irow1); d0-=dv*dval0; d1-=dv*dval1; SHIFT_REF(dwork1, irow0)=d0; SHIFT_REF(dwork1, irow1)=d1; } #endif /* put this down here so that dv is less likely to cause a stall */ if (fabs(dv) >= tolerance) { int iput=hpivro[ipiv]; *dworko++=dv; *mptX++=iput-1; } } dv = dwork1[next_ipiv]; ipiv=next_ipiv; } /* endwhile */ *mptp = mptX; *ip = ipiv; } static void c_ekkftjup_aux3_pack(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dworko, const int * COIN_RESTRICT back, const int * COIN_RESTRICT hpivro, int *ipivp, int loop_limit, int **mptXp) { double tolerance = fact->zeroTolerance; int ipiv = *ipivp; if (ipiv!=loop_limit) { int *mptX = *mptXp; double dv = dwork1[ipiv]; do { int next_ipiv = back[ipiv]; double next_dv=dwork1[next_ipiv]; dwork1[ipiv]=0.0; if (fabs(dv)>=tolerance) { int iput=hpivro[ipiv]; *dworko++=dv; *mptX++=iput-1; } ipiv = next_ipiv; dv = next_dv; } while (ipiv!=loop_limit); *mptXp = mptX; *ipivp = ipiv; } } /* do not use return value if mpt==0 */ /* using dual, this is usually called via c_ekkftrn_ft, from c_ekksdul * (so mpt is non-null). * it is generally called every iteration, but sometimes several iterations * are skipped (null moves?). * * generally, back[i] == i-1 (initialized in c_ekkshfv towards the end). */ static int c_ekkftjup_pack(COIN_REGISTER3 const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, int last, double * COIN_RESTRICT dworko , int * COIN_RESTRICT mpt) { const double * COIN_RESTRICT dluval = fact->xeeadr; const int * COIN_RESTRICT hrowi = fact->xeradr; const int * COIN_RESTRICT mcstrt = fact->xcsadr; const int * COIN_RESTRICT hpivro = fact->krpadr; double tolerance = fact->zeroTolerance; int ndenuc=fact->ndenuc; const int first_dense=fact->first_dense; const int last_dense=fact->last_dense; int * mptX = mpt; int * mptY = mpt; const int nrow = fact->nrow; const int * COIN_RESTRICT back=fact->back; int ipiv=back[nrow+1]; assert (mpt); if (last_dense>first_dense&&mcstrt[ipiv]>=mcstrt[last_dense]) { c_ekkftjup_scan_aux_pack(fact, dwork1, dworko, last_dense, &ipiv, &mptX ); /* adjust */ dworko+= (mptX-mpt); mpt=mptX; { int j; int n=0; const int firstDense = nrow- ndenuc+1; double *densew = &dwork1[firstDense]; int offset; /* check first dense to see where in triangle it is */ int last=first_dense; const int k1=mcstrt[last]; const int k2=k1+hrowi[k1]; for (j=k2; j>k1; j--) { int irow = UNSHIFT_INDEX(hrowi[j]); if (irow=tolerance) { int iput=hpivro[ipiv]; *dworko++=-dv; *mptX++=iput-1; } ipiv = next_ipiv; } return static_cast(mptX-mptY); } static int c_ekkftju_sparse_a(COIN_REGISTER2 const EKKfactinfo * COIN_RESTRICT2 fact, int * COIN_RESTRICT mpt, int nincol,int * COIN_RESTRICT spare) { const int * COIN_RESTRICT hrowi = fact->xeradr+1; const int * COIN_RESTRICT mcstrt = fact->xcsadr; const int nrow = fact->nrow; char * COIN_RESTRICT nonzero=fact->nonzero; int k,nStack,kx,nel; int nList=0; int iPivot; /*int kkk=nincol;*/ int * COIN_RESTRICT list = spare; int * COIN_RESTRICT stack = spare+nrow; int * COIN_RESTRICT next = stack+nrow; for (k=0;kxeeadr+1; const int * COIN_RESTRICT hrowi = fact->xeradr+1; const int * COIN_RESTRICT mcstrt = fact->xcsadr; const int * COIN_RESTRICT hpivro = fact->krpadr; double tolerance = fact->zeroTolerance; char * COIN_RESTRICT nonzero=fact->nonzero; int i,k,kx,nel; int iPivot; /*int kkk=nincol;*/ int * COIN_RESTRICT list = spare; i=nList-1; nList=0; for (;i>=0;i--) { double dpiv; double dv; iPivot = list[i]; /*printf("pivot %d %d\n",i,iPivot);*/ dv=dwork1[iPivot]; kx = mcstrt[iPivot]; nel = hrowi[kx-1]; dwork1[iPivot]=0.0; dpiv = dluval[kx-1]; dv*=dpiv; nonzero[iPivot]=0; iPivot=hpivro[iPivot]; if (fabs(dv)>=tolerance) { *dworko++=dv; mpt[nList++]=iPivot-1; for (k = kx; k < kx+nel; k++) { double dval; double dd; int irow = hrowi[k]; dval=dluval[k]; dd=dwork1[irow]; dd-=dv*dval; dwork1[irow]=dd; } } } return (nList); } /* dwork1 = (B^-1)dwork1; * I think dpermu[1..nrow+1] is zeroed on exit (?) * I don't think it is expected to have any particular value on entry (?) */ int c_ekkftrn(COIN_REGISTER const EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dpermu, int * COIN_RESTRICT mpt,int numberNonZero) { const int * COIN_RESTRICT mpermu = fact->mpermu; int lastNonZero; int firstNonZero = c_ekkshfpi_list2(mpermu+1, dwork1+1, dpermu, mpt, numberNonZero,&lastNonZero); if (fact->nnentl&&lastNonZero>=fact->firstLRow) { /* dpermu = (L^-1)dpermu */ c_ekkftj4p(fact, dpermu, firstNonZero); } int lastSlack; /* dpermu = (R^-1) dpermu */ c_ekkftjl(fact, dpermu); assert (fact->numberSlacks!=0||!fact->lastSlack); lastSlack=fact->lastSlack; /* dwork1 = (U^-1)dpermu; dpermu zeroed (?) */ return c_ekkftjup(fact, dpermu, lastSlack, dwork1, mpt); } /* c_ekkftrn */ int c_ekkftrn_ft(COIN_REGISTER EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1_ft, int * COIN_RESTRICT mpt_ft, int *nincolp_ft) { double * COIN_RESTRICT dpermu_ft = fact->kadrpm; int * COIN_RESTRICT spare = reinterpret_cast(fact->kp1adr); int nincol = *nincolp_ft; int nuspik; double * COIN_RESTRICT dluvalPut = fact->xeeadr+fact->nnentu+1; int * COIN_RESTRICT hrowiPut = fact->xeradr+fact->nnentu+1; const int nrow = fact->nrow; /* mpermu contains the permutation */ const int * COIN_RESTRICT mpermu=fact->mpermu; int lastSlack; int kdnspt = fact->nnetas - fact->nnentl; bool isRoom = (fact->nnentu + (nrow << 1) < (kdnspt - 2) + fact->R_etas_start[fact->nR_etas + 1]); /* say F-T will be sorted */ fact->sortedEta=1; assert (fact->numberSlacks!=0||!fact->lastSlack); lastSlack=fact->lastSlack; #ifdef CLP_REUSE_ETAS bool skipStuff = (fact->reintro>=0); int save_nR_etas=fact->nR_etas; int * save_hpivcoR=fact->hpivcoR; int * save_R_etas_start=fact->R_etas_start; if (skipStuff) { // just move int * putSeq = fact->xrsadr+2*fact->nrowmx+2; int * position = putSeq+fact->maxinv; int * putStart = position+fact->maxinv; memset(dwork1_ft,0,nincol*sizeof(double)); int iPiv=fact->reintro; int start=putStart[iPiv]&0x7fffffff; int end=putStart[iPiv+1]&0x7fffffff; double * COIN_RESTRICT dluval = fact->xeeadr; int * COIN_RESTRICT hrowi = fact->xeradr; double dValue; if (fact->reintronrow) { iPiv++; dValue=1.0/dluval[start++]; } else { iPiv=hrowi[--end]; dValue=dluval[end]; start++; int ndoSkip=0; for (int i=fact->nrow;ireintro;i++) { if ((putStart[i]&0x80000000)==0) ndoSkip++; } fact->nR_etas-=ndoSkip; fact->hpivcoR+=ndoSkip; fact->R_etas_start+=ndoSkip; } dpermu_ft[iPiv]=dValue; if (fact->if_sparse_update>0 && DENSE_THRESHOLDif_sparse_update>0 && DENSE_THRESHOLDnnentl) { nincol = c_ekkftj4_sparse(fact, dpermu_ft, mpt_ft, nincol,spare); } } /* DO ROW ETAS IN L */ if (isRoom) { ++fact->nnentu; nincol= c_ekkftjl_sparse3(fact, dpermu_ft, mpt_ft, hrowiPut, dluvalPut,nincol); nuspik = nincol; /* temporary */ /* say not sorted */ fact->sortedEta=0; } else { /* no room */ nuspik=-3; nincol= c_ekkftjl_sparse2(fact, dpermu_ft, mpt_ft, nincol); } /* DO U */ if (DENSE_THRESHOLD>nrow-fact->numberSlacks) { nincol = c_ekkftjup_pack(fact, dpermu_ft,lastSlack, dwork1_ft, mpt_ft); } else { nincol= c_ekkftju_sparse_a(fact, mpt_ft, nincol, spare); nincol = c_ekkftju_sparse_b(fact, dpermu_ft, dwork1_ft , mpt_ft, nincol, spare); } } else { if (!skipStuff) { int lastNonZero; int firstNonZero = c_ekkshfpi_list(mpermu+1, dwork1_ft, dpermu_ft, mpt_ft, nincol,&lastNonZero); if (fact->nnentl&&lastNonZero>=fact->firstLRow) { /* dpermu_ft = (L^-1)dpermu_ft */ c_ekkftj4p(fact, dpermu_ft, firstNonZero); } } /* dpermu_ft = (R^-1) dpermu_ft */ c_ekkftjl(fact, dpermu_ft); if (isRoom) { /* fake start to allow room for pivot */ /* dluval[fact->nnentu...] = non-zeros of dpermu_ft; * hrowi[fact->nnentu..] = indices of these non-zeros; * near-zeros in dluval flattened */ ++fact->nnentu; nincol= c_ekkscmv(fact,fact->nrow, dpermu_ft, hrowiPut, dluvalPut); /* * note that this is not the value of nincol determined by c_ekkftjup. * For Forrest-Tomlin update we want vector before U * this vector will replace one in U */ nuspik = nincol; } else { /* no room */ nuspik = -3; } /* dwork1_ft = (U^-1)dpermu_ft; dpermu_ft zeroed (?) */ nincol = c_ekkftjup_pack(fact, dpermu_ft, lastSlack, dwork1_ft, mpt_ft); } #ifdef CLP_REUSE_ETAS fact->nR_etas=save_nR_etas; fact->hpivcoR=save_hpivcoR; fact->R_etas_start=save_R_etas_start; #endif *nincolp_ft = nincol; return (nuspik); } /* c_ekkftrn */ void c_ekkftrn2(COIN_REGISTER EKKfactinfo * COIN_RESTRICT2 fact, double * COIN_RESTRICT dwork1, double * COIN_RESTRICT dpermu1,int * COIN_RESTRICT mpt1, int *nincolp, double * COIN_RESTRICT dwork1_ft, int * COIN_RESTRICT mpt_ft, int *nincolp_ft) { double * COIN_RESTRICT dluvalPut = fact->xeeadr+fact->nnentu+1; int * COIN_RESTRICT hrowiPut = fact->xeradr+fact->nnentu+1; const int nrow = fact->nrow; /* mpermu contains the permutation */ const int * COIN_RESTRICT mpermu=fact->mpermu; int lastSlack; assert (fact->numberSlacks!=0||!fact->lastSlack); lastSlack=fact->lastSlack; int nincol = *nincolp_ft; /* using dwork1 instead double *dpermu_ft = fact->kadrpm; */ int * spare = reinterpret_cast(fact->kp1adr); int kdnspt = fact->nnetas - fact->nnentl; bool isRoom = (fact->nnentu + (nrow << 1) < (kdnspt - 2) + fact->R_etas_start[fact->nR_etas + 1]); /* say F-T will be sorted */ fact->sortedEta=1; int lastNonZero; int firstNonZero = c_ekkshfpi_list2(mpermu+1, dwork1+1, dpermu1, mpt1, *nincolp,&lastNonZero); if (fact->nnentl&&lastNonZero>=fact->firstLRow) { /* dpermu1 = (L^-1)dpermu1 */ c_ekkftj4p(fact, dpermu1, firstNonZero); } #ifdef CLP_REUSE_ETAS bool skipStuff = (fact->reintro>=0); int save_nR_etas=fact->nR_etas; int * save_hpivcoR=fact->hpivcoR; int * save_R_etas_start=fact->R_etas_start; if (skipStuff) { // just move int * putSeq = fact->xrsadr+2*fact->nrowmx+2; int * position = putSeq+fact->maxinv; int * putStart = position+fact->maxinv; memset(dwork1_ft,0,nincol*sizeof(double)); int iPiv=fact->reintro; int start=putStart[iPiv]&0x7fffffff; int end=putStart[iPiv+1]&0x7fffffff; double * COIN_RESTRICT dluval = fact->xeeadr; int * COIN_RESTRICT hrowi = fact->xeradr; double dValue; if (fact->reintronrow) { iPiv++; dValue=1.0/dluval[start++]; } else { iPiv=hrowi[--end]; dValue=dluval[end]; start++; int ndoSkip=0; for (int i=fact->nrow;ireintro;i++) { if ((putStart[i]&0x80000000)==0) ndoSkip++; } fact->nR_etas-=ndoSkip; fact->hpivcoR+=ndoSkip; fact->R_etas_start+=ndoSkip; } dwork1[iPiv]=dValue; if (fact->if_sparse_update>0 && DENSE_THRESHOLDif_sparse_update>0 && DENSE_THRESHOLDnnentl) { nincol = c_ekkftj4_sparse(fact, dwork1, mpt_ft, nincol,spare); } } /* DO ROW ETAS IN L */ if (isRoom) { ++fact->nnentu; nincol= c_ekkftjl_sparse3(fact, dwork1, mpt_ft, hrowiPut, dluvalPut, nincol); fact->nuspike = nincol; /* say not sorted */ fact->sortedEta=0; } else { /* no room */ fact->nuspike=-3; nincol= c_ekkftjl_sparse2(fact, dwork1, mpt_ft, nincol); } } else { if (!skipStuff) { int lastNonZero; int firstNonZero = c_ekkshfpi_list(mpermu+1, dwork1_ft, dwork1, mpt_ft, nincol,&lastNonZero); if (fact->nnentl&&lastNonZero>=fact->firstLRow) { /* dpermu_ft = (L^-1)dpermu_ft */ c_ekkftj4p(fact, dwork1, firstNonZero); } } c_ekkftjl(fact, dwork1); if (isRoom) { /* fake start to allow room for pivot */ /* dluval[fact->nnentu...] = non-zeros of dpermu_ft; * hrowi[fact->nnentu..] = indices of these non-zeros; * near-zeros in dluval flattened */ ++fact->nnentu; nincol= c_ekkscmv(fact,fact->nrow, dwork1, hrowiPut, dluvalPut); /* * note that this is not the value of nincol determined by c_ekkftjup. * For Forrest-Tomlin update we want vector before U * this vector will replace one in U */ fact->nuspike = nincol; } else { /* no room */ fact->nuspike = -3; } } #ifdef CLP_REUSE_ETAS fact->nR_etas=save_nR_etas; fact->hpivcoR=save_hpivcoR; fact->R_etas_start=save_R_etas_start; #endif /* dpermu1 = (R^-1) dpermu1 */ c_ekkftjl(fact, dpermu1); /* DO U */ if (fact->if_sparse_update<=0 || DENSE_THRESHOLD>nrow-fact->numberSlacks) { nincol = c_ekkftjup_pack(fact, dwork1,lastSlack, dwork1_ft, mpt_ft); } else { nincol= c_ekkftju_sparse_a(fact, mpt_ft, nincol, spare); nincol = c_ekkftju_sparse_b(fact, dwork1, dwork1_ft , mpt_ft, nincol, spare); } *nincolp_ft = nincol; /* dwork1 = (U^-1)dpermu1; dpermu1 zeroed (?) */ *nincolp = c_ekkftjup(fact, dpermu1,lastSlack, dwork1, mpt1); }