MYBOOL crash_basis(lprec *lp) { int i; MATrec *mat = lp->matA; MYBOOL ok = TRUE; /* Initialize basis indicators */ if(lp->basis_valid) lp->var_basic[0] = FALSE; else default_basis(lp); /* Set initial partial pricing blocks */ if(lp->rowblocks != NULL) lp->rowblocks->blocknow = 1; if(lp->colblocks != NULL) lp->colblocks->blocknow = ((lp->crashmode == CRASH_NONE) || (lp->colblocks->blockcount == 1) ? 1 : 2); /* Construct a basis that is in some measure the "most feasible" */ if((lp->crashmode == CRASH_MOSTFEASIBLE) && mat_validate(mat)) { /* The logic here follows Maros */ LLrec *rowLL = NULL, *colLL = NULL; int ii, rx, cx, ix, nz; REAL wx, tx, *rowMAX = NULL, *colMAX = NULL; int *rowNZ = NULL, *colNZ = NULL, *rowWT = NULL, *colWT = NULL; REAL *value; int *rownr, *colnr; report(lp, NORMAL, "crash_basis: 'Most feasible' basis crashing selected\n"); /* Tally row and column non-zero counts */ ok = allocINT(lp, &rowNZ, lp->rows+1, TRUE) && allocINT(lp, &colNZ, lp->columns+1, TRUE) && allocREAL(lp, &rowMAX, lp->rows+1, FALSE) && allocREAL(lp, &colMAX, lp->columns+1, FALSE); if(!ok) goto Finish; nz = mat_nonzeros(mat); rownr = &COL_MAT_ROWNR(0); colnr = &COL_MAT_COLNR(0); value = &COL_MAT_VALUE(0); for(i = 0; i < nz; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) { rx = *rownr; cx = *colnr; wx = fabs(*value); rowNZ[rx]++; colNZ[cx]++; if(i == 0) { rowMAX[rx] = wx; colMAX[cx] = wx; colMAX[0] = wx; } else { SETMAX(rowMAX[rx], wx); SETMAX(colMAX[cx], wx); SETMAX(colMAX[0], wx); } } /* Reduce counts for small magnitude to preserve stability */ rownr = &COL_MAT_ROWNR(0); colnr = &COL_MAT_COLNR(0); value = &COL_MAT_VALUE(0); for(i = 0; i < nz; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) { rx = *rownr; cx = *colnr; wx = fabs(*value); #ifdef CRASH_SIMPLESCALE if(wx < CRASH_THRESHOLD * colMAX[0]) { rowNZ[rx]--; colNZ[cx]--; } #else if(wx < CRASH_THRESHOLD * rowMAX[rx]) rowNZ[rx]--; if(wx < CRASH_THRESHOLD * colMAX[cx]) colNZ[cx]--; #endif } /* Set up priority tables */ ok = allocINT(lp, &rowWT, lp->rows+1, TRUE); createLink(lp->rows, &rowLL, NULL); ok &= (rowLL != NULL); if(!ok) goto Finish; for(i = 1; i <= lp->rows; i++) { if(get_constr_type(lp, i)==EQ) ii = 3; else if(lp->upbo[i] < lp->infinite) ii = 2; else if(fabs(lp->rhs[i]) < lp->infinite) ii = 1; else ii = 0; rowWT[i] = ii; if(ii > 0) appendLink(rowLL, i); } ok = allocINT(lp, &colWT, lp->columns+1, TRUE); createLink(lp->columns, &colLL, NULL); ok &= (colLL != NULL); if(!ok) goto Finish; for(i = 1; i <= lp->columns; i++) { ix = lp->rows+i; if(is_unbounded(lp, i)) ii = 3; else if(lp->upbo[ix] >= lp->infinite) ii = 2; else if(fabs(lp->upbo[ix]-lp->lowbo[ix]) > lp->epsmachine) ii = 1; else ii = 0; colWT[i] = ii; if(ii > 0) appendLink(colLL, i); } /* Loop over all basis variables */ for(i = 1; i <= lp->rows; i++) { /* Select row */ rx = 0; wx = -lp->infinite; for(ii = firstActiveLink(rowLL); ii > 0; ii = nextActiveLink(rowLL, ii)) { tx = rowWT[ii] - CRASH_SPACER*rowNZ[ii]; if(tx > wx) { rx = ii; wx = tx; } } if(rx == 0) break; removeLink(rowLL, rx); /* Select column */ cx = 0; wx = -lp->infinite; for(ii = mat->row_end[rx-1]; ii < mat->row_end[rx]; ii++) { /* Update NZ column counts for row selected above */ tx = fabs(ROW_MAT_VALUE(ii)); ix = ROW_MAT_COLNR(ii); #ifdef CRASH_SIMPLESCALE if(tx >= CRASH_THRESHOLD * colMAX[0]) #else if(tx >= CRASH_THRESHOLD * colMAX[ix]) #endif colNZ[ix]--; if(!isActiveLink(colLL, ix) || (tx < CRASH_THRESHOLD * rowMAX[rx])) continue; /* Now do the test for best pivot */ tx = my_sign(lp->orig_obj[ix]) - my_sign(ROW_MAT_VALUE(ii)); tx = colWT[ix] + CRASH_WEIGHT*tx - CRASH_SPACER*colNZ[ix]; if(tx > wx) { cx = ix; wx = tx; } } if(cx == 0) break; removeLink(colLL, cx); /* Update row NZ counts */ ii = mat->col_end[cx-1]; rownr = &COL_MAT_ROWNR(ii); value = &COL_MAT_VALUE(ii); for(; ii < mat->col_end[cx]; ii++, rownr += matRowColStep, value += matValueStep) { wx = fabs(*value); ix = *rownr; #ifdef CRASH_SIMPLESCALE if(wx >= CRASH_THRESHOLD * colMAX[0]) #else if(wx >= CRASH_THRESHOLD * rowMAX[ix]) #endif rowNZ[ix]--; } /* Set new basis variable */ set_basisvar(lp, rx, lp->rows+cx); } /* Clean up */ Finish: FREE(rowNZ); FREE(colNZ); FREE(rowMAX); FREE(colMAX); FREE(rowWT); FREE(colWT); freeLink(&rowLL); freeLink(&colLL); } /* Construct a basis that is in some measure the "least degenerate" */ else if((lp->crashmode == CRASH_LEASTDEGENERATE) && mat_validate(mat)) { /* The logic here follows Maros */ LLrec *rowLL = NULL, *colLL = NULL; int ii, rx, cx, ix, nz, *merit = NULL; REAL *value, wx, hold, *rhs = NULL, *eta = NULL; int *rownr, *colnr; report(lp, NORMAL, "crash_basis: 'Least degenerate' basis crashing selected\n"); /* Create temporary arrays */ ok = allocINT(lp, &merit, lp->columns + 1, FALSE) && allocREAL(lp, &eta, lp->rows + 1, FALSE) && allocREAL(lp, &rhs, lp->rows + 1, FALSE); createLink(lp->columns, &colLL, NULL); createLink(lp->rows, &rowLL, NULL); ok &= (colLL != NULL) && (rowLL != NULL); if(!ok) goto FinishLD; MEMCOPY(rhs, lp->orig_rhs, lp->rows + 1); for(i = 1; i <= lp->columns; i++) appendLink(colLL, i); for(i = 1; i <= lp->rows; i++) appendLink(rowLL, i); /* Loop until we have found enough new bases */ while(colLL->count > 0) { /* Tally non-zeros matching in RHS and each active column */ nz = mat_nonzeros(mat); rownr = &COL_MAT_ROWNR(0); colnr = &COL_MAT_COLNR(0); ii = 0; MEMCLEAR(merit, lp->columns + 1); for(i = 0; i < nz; i++, rownr += matRowColStep, colnr += matRowColStep) { rx = *rownr; cx = *colnr; if(isActiveLink(colLL, cx) && (rhs[rx] != 0)) { merit[cx]++; ii++; } } if(ii == 0) break; /* Find maximal match; break ties with column length */ i = firstActiveLink(colLL); cx = i; for(i = nextActiveLink(colLL, i); i != 0; i = nextActiveLink(colLL, i)) { if(merit[i] >= merit[cx]) { if((merit[i] > merit[cx]) || (mat_collength(mat, i) > mat_collength(mat, cx))) cx = i; } } /* Determine the best pivot row */ i = mat->col_end[cx-1]; nz = mat->col_end[cx]; rownr = &COL_MAT_ROWNR(i); value = &COL_MAT_VALUE(i); rx = 0; wx = 0; MEMCLEAR(eta, lp->rows + 1); for(; i < nz; i++, rownr += matRowColStep, value += matValueStep) { ix = *rownr; hold = *value; eta[ix] = rhs[ix] / hold; hold = fabs(hold); if(isActiveLink(rowLL, ix) && (hold > wx)) { wx = hold; rx = ix; } } /* Set new basis variable */ if(rx > 0) { /* We have to update the rhs vector for the implied transformation in order to be able to find the new RHS non-zero pattern */ for(i = 1; i <= lp->rows; i++) rhs[i] -= wx * eta[i]; rhs[rx] = wx; /* Do the exchange */ set_basisvar(lp, rx, lp->rows+cx); removeLink(rowLL, rx); } removeLink(colLL, cx); } /* Clean up */ FinishLD: FREE(merit); FREE(rhs); freeLink(&rowLL); freeLink(&colLL); } return( ok ); }
STATIC MYBOOL SOS_shift_col(SOSgroup *group, int sosindex, int column, int delta, LLrec *usedmap, MYBOOL forceresort) /* Routine to adjust SOS indeces for variable insertions or deletions; Note: SOS_shift_col must be called before make_SOSchain! */ { int i, ii, n, nn, nr; int changed; int *list; REAL *weights; #ifdef Paranoia lprec *lp = group->lp; if((sosindex < 0) || (sosindex > group->sos_count)) { report(lp, IMPORTANT, "SOS_shift_col: Invalid SOS index %d\n", sosindex); return(FALSE); } else if((column < 1) || (delta == 0)) { report(lp, IMPORTANT, "SOS_shift_col: Invalid column %d specified with delta %d\n", column, delta); return(FALSE); } #endif if((sosindex == 0) && (group->sos_count == 1)) sosindex = 1; if(sosindex == 0) { for(i = 1; i <= group->sos_count; i++) { if(!SOS_shift_col(group, i, column, delta, usedmap, forceresort)) return(FALSE); } } else { list = group->sos_list[sosindex-1]->members; weights = group->sos_list[sosindex-1]->weights; n = list[0]; nn = list[n+1]; /* Case where variable indeces are to be incremented */ if(delta > 0) { for(i = 1; i <= n; i++) { if(list[i] >= column) list[i] += delta; } } /* Case where variables are to be deleted/indeces decremented */ else { changed = 0; if(usedmap != NULL) { int *newidx = NULL; /* Defer creation of index mapper until we are sure that a member of this SOS is actually targeted for deletion */ if(newidx == NULL) { allocINT(group->lp, &newidx, group->lp->columns+1, TRUE); for(i = firstActiveLink(usedmap), ii = 1; i != 0; i = nextActiveLink(usedmap, i), ii++) newidx[i] = ii; } for(i = 1, ii = 0; i <= n; i++) { nr = list[i]; /* Check if this SOS variable should be deleted */ if(!isActiveLink(usedmap, nr)) continue; /* If the index is "high" then make adjustment and shift */ changed++; ii++; list[ii] = newidx[nr]; weights[ii] = weights[i]; } FREE(newidx); } else for(i = 1, ii = 0; i <= n; i++) { nr = list[i]; /* Check if this SOS variable should be deleted */ if((nr >= column) && (nr < column-delta)) continue; /* If the index is "high" then decrement */ if(nr > column) { changed++; nr += delta; } ii++; list[ii] = nr; weights[ii] = weights[i]; } /* Update the SOS length / type indicators */ if(ii < n) { list[0] = ii; list[ii+1] = nn; } /* Update mapping arrays to search large SOS's faster */ if(forceresort && ((ii < n) || (changed > 0))) SOS_member_sortlist(group, sosindex); } } return(TRUE); }
/* LOCAL HELPER ROUTINE */ int bfp_LUSOLfactorize(lprec *lp, MYBOOL *usedpos, int *rownum, int *singular) { int i, j, nz, deltarows = bfp_rowoffset(lp); INVrec *invB = lp->invB; /* Handle normal, presumed nonsingular case */ if(singular == NULL) { /* Optionally do a symbolic minimum degree ordering; not that slack variables should not be processed */ /*#define UsePreprocessMDO*/ #ifdef UsePreprocessMDO int *mdo; mdo = lp->bfp_createMDO(lp, usedpos, lp->rows, TRUE); if(mdo != NULL) { for(i = 1; i <= lp->rows; i++) lp->set_basisvar(lp, i, mdo[i]); FREE(mdo); } #endif /* Reset the factorization engine */ LUSOL_clear(invB->LUSOL, TRUE); /* Add the basis columns in the original order */ for(i = 1; i <= invB->dimcount; i++) { nz = lp->get_basiscolumn(lp, i, rownum, invB->value); LUSOL_loadColumn(invB->LUSOL, rownum, i, invB->value, nz, 0); if((i > deltarows) && (lp->var_basic[i-deltarows] > lp->rows)) lp->invB->user_colcount++; } /* Factorize */ i = LUSOL_factorize(invB->LUSOL); } /* Handle case where a column may be singular */ else { LLrec *map; /* Reset the factorization engine */ i = bfp_LUSOLidentity(lp, rownum); /* Build map of available columns */ nz = createLink(lp->rows, &map, NULL); for(i = 1; i <= lp->rows; i++) { if(lp->var_basic[i] <= lp->rows) removeLink(map, i); } /* Rebuild the basis, column by column, while skipping slack columns */ j = firstActiveLink(map); for(i = 1; i <= lp->rows; i++) { if(lp->var_basic[i] <= lp->rows) continue; nz = bfp_LUSOLsetcolumn(lp, j+deltarows, lp->var_basic[i]); if(nz == LUSOL_INFORM_LUSUCCESS) lp->invB->user_colcount++; else { nz = bfp_LUSOLsetcolumn(lp, j+deltarows, i); lp->set_basisvar(lp, i, i); } j = nextActiveLink(map, j); } /* Sort the basis list */ MEMCOPY(rownum, lp->var_basic, lp->rows+1); sortByINT(lp->var_basic, rownum, lp->rows, 1, TRUE); } return( i ); }