/* ---------------------------------------------------------------------------------- Crash management routines in lp_solve v5.0+ ---------------------------------------------------------------------------------- Author: Kjell Eikland Contact: kjell.eikland@broadpark.no License terms: LGPL. Requires: lp_lib.h, lp_utils.h, lp_matrix.h Release notes: v1.0.0 1 April 2004 First version. v1.1.0 20 July 2004 Reworked with flexible matrix storage model. ---------------------------------------------------------------------------------- */ #include #include "commonlib.h" #include "lp_lib.h" #include "lp_scale.h" #include "lp_utils.h" #include "lp_report.h" #include "lp_matrix.h" #include "lp_crash.h" #ifdef FORTIFY # include "lp_fortify.h" #endif 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 ); } #if 0 MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector) { MYBOOL status = FALSE; REAL *values = NULL, *violation = NULL, *value, error, upB, loB, sortorder = 1.0; int i, n, *rownr, *colnr; MATrec *mat = lp->matA; if(!mat_validate(lp->matA)) return( status ); /* Create helper arrays */ if(!allocREAL(lp, &values, lp->sum+1, TRUE) || !allocREAL(lp, &violation, lp->sum+1, TRUE)) goto Finish; /* Compute values of slack variables for given guess vector */ i = 0; n = get_nonzeros(lp); rownr = &COL_MAT_ROWNR(i); colnr = &COL_MAT_COLNR(i); value = &COL_MAT_VALUE(i); for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) * guessvector[*colnr]; MEMMOVE(values+lp->rows+1, guessvector+1, lp->columns); /* Initialize constraint bound violation measures */ for(i = 1; i <= lp->rows; i++) { upB = get_rh_upper(lp, i); loB = get_rh_lower(lp, i); error = values[i] - upB; if(error > lp->epsprimal) violation[i] = sortorder*error; else { error = loB - values[i]; if(error > lp->epsprimal) violation[i] = sortorder*error; else if(is_infinite(lp, loB) && is_infinite(lp, upB)) ; else if(is_infinite(lp, upB)) violation[i] = sortorder*(loB - values[i]); else if(is_infinite(lp, loB)) violation[i] = sortorder*(values[i] - upB); else violation[i] = - sortorder*MAX(upB - values[i], values[i] - loB); } basisvector[i] = i; } /* Initialize user variable bound violation measures */ for(i = 1; i <= lp->columns; i++) { n = lp->rows+i; upB = get_upbo(lp, i); loB = get_lowbo(lp, i); error = guessvector[i] - upB; if(error > lp->epsprimal) violation[n] = sortorder*error; else { error = loB - values[n]; if(error > lp->epsprimal) violation[n] = sortorder*error; else if(is_infinite(lp, loB) && is_infinite(lp, upB)) ; else if(is_infinite(lp, upB)) violation[n] = sortorder*(loB - values[n]); else if(is_infinite(lp, loB)) violation[n] = sortorder*(values[n] - upB); else violation[n] = - sortorder*MAX(upB - values[n], values[n] - loB); } basisvector[n] = n; } /* Sort decending by violation; this means that variables with the largest violations will be designated as basic */ sortByREAL(basisvector, violation, lp->sum, 1, FALSE); /* Adjust the non-basic indeces for the (proximal) bound state */ error = lp->epsprimal; for(i = lp->rows+1, rownr = basisvector+i; i <= lp->sum; i++, rownr++) { if(*rownr <= lp->rows) { if(values[*rownr] <= get_rh_lower(lp, *rownr)+error) *rownr = -(*rownr); } else if(values[i] <= get_lowbo(lp, (*rownr)-lp->rows)+error) *rownr = -(*rownr); } /* Clean up and return status */ status = (MYBOOL) (violation[1] == 0); Finish: FREE(values); FREE(violation); return( status ); } #endif #if 0 MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector) { MYBOOL *isnz, status = FALSE; REAL *values = NULL, *violation = NULL, eps = lp->epsprimal, *value, error, upB, loB, sortorder = 1.0; int i, j, n, *rownr, *colnr, *slkpos, nrows = lp->rows, ncols = lp->columns; MATrec *mat = lp->matA; if(!mat_validate(mat)) return( status ); /* Create helper arrays */ if(!allocREAL(lp, &values, lp->sum+1, TRUE) || !allocREAL(lp, &violation, lp->sum+1, TRUE)) goto Finish; /* Compute values of slack variables for given guess vector */ i = 0; n = get_nonzeros(lp); rownr = &COL_MAT_ROWNR(i); colnr = &COL_MAT_COLNR(i); value = &COL_MAT_VALUE(i); for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) * guessvector[*colnr]; MEMMOVE(values+nrows+1, guessvector+1, ncols); /* Initialize constraint bound violation measures (expressed as positive values) */ for(i = 1; i <= nrows; i++) { upB = get_rh_upper(lp, i); loB = get_rh_lower(lp, i); error = values[i] - upB; if(error > eps) violation[i] = sortorder*error; else { error = loB - values[i]; if(error > eps) violation[i] = sortorder*error; else if(my_infinite(lp, loB) && my_infinite(lp, upB)) ; else if(my_infinite(lp, upB)) violation[i] = sortorder*(loB - values[i]); else if(my_infinite(lp, loB)) violation[i] = sortorder*(values[i] - upB); else violation[i] = -sortorder*MAX(upB - values[i], values[i] - loB); } basisvector[i] = i; } /* Initialize user variable bound violation measures (expressed as positive values) */ for(i = 1; i <= ncols; i++) { n = nrows+i; upB = get_upbo(lp, i); loB = get_lowbo(lp, i); error = guessvector[i] - upB; if(error > eps) violation[n] = sortorder*error; else { error = loB - values[n]; if(error > eps) violation[n] = sortorder*error; else if(my_infinite(lp, loB) && my_infinite(lp, upB)) ; else if(my_infinite(lp, upB)) violation[n] = sortorder*(loB - values[n]); else if(my_infinite(lp, loB)) violation[n] = sortorder*(values[n] - upB); else violation[n] = -sortorder*MAX(upB - values[n], values[n] - loB); } basisvector[n] = n; } /* Sort decending by violation; this means that variables with the largest violations will be designated as basic */ sortByREAL(basisvector, violation, lp->sum, 1, FALSE); error = violation[1]; /* Adjust the non-basic indeces for the (proximal) bound state */ for(i = nrows+1, rownr = basisvector+i; i <= lp->sum; i++, rownr++) { if(*rownr <= nrows) { if(values[*rownr] <= get_rh_lower(lp, *rownr)+eps) *rownr = -(*rownr); } else if(values[i] <= get_lowbo(lp, (*rownr)-nrows)+eps) *rownr = -(*rownr); } #if 1 /* Let us check for obvious row singularities and try to fix these; First assemble necessary basis statistics... */ isnz = (MYBOOL *) values; MEMCLEAR(isnz, nrows+1); slkpos = (int *) violation; MEMCLEAR(slkpos, nrows+1); for(i = 1; i <= nrows; i++) { j = abs(basisvector[i]); if(j <= nrows) { isnz[j] = TRUE; slkpos[j] = i; } else { j-= nrows; j = mat->col_end[j-1]; isnz[COL_MAT_ROWNR(j)] = TRUE; /*isnz[COL_MAT_ROWNR(j+1)] = TRUE;*/ } } for(; i <= lp->sum; i++) { j = abs(basisvector[i]); if(j <= nrows) slkpos[j] = i; } /* ...then set the corresponding slacks basic for row rank deficient positions */ for(j = 1; j <= nrows; j++) { #ifdef Paranoia if(slkpos[j] == 0) report(lp, SEVERE, "guess_basis: Internal error"); #endif if(!isnz[j]) { isnz[j] = TRUE; i = slkpos[j]; swapINT(&basisvector[i], &basisvector[j]); basisvector[j] = abs(basisvector[j]); } } #endif /* Clean up and return status */ status = (MYBOOL) (error <= eps); Finish: FREE(values); FREE(violation); return( status ); } #endif #if 0 MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector) { MYBOOL *isnz, status = FALSE; REAL *values = NULL, *violation = NULL, eps = lp->epsprimal, *value, error, upB, loB, sortorder = 1.0; int i, j, jj, n, *rownr, *colnr, *slkpos, nrows = lp->rows, ncols = lp->columns; MATrec *mat = lp->matA; if(!mat_validate(mat)) return( status ); /* Create helper arrays */ if(!allocREAL(lp, &values, lp->sum+1, TRUE) || !allocREAL(lp, &violation, lp->sum+1, TRUE)) goto Finish; /* Compute values of slack variables for given guess vector */ i = 0; n = get_nonzeros(lp); rownr = &COL_MAT_ROWNR(i); colnr = &COL_MAT_COLNR(i); value = &COL_MAT_VALUE(i); for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) * guessvector[*colnr]; MEMMOVE(values+nrows+1, guessvector+1, ncols); /* Initialize constraint bound violation measures (expressed as positive values) */ for(i = 1; i <= nrows; i++) { upB = get_rh_upper(lp, i); loB = get_rh_lower(lp, i); error = values[i] - upB; if(error > -eps) violation[i] = sortorder*MAX(0,error); else { error = loB - values[i]; if(error > -eps) violation[i] = sortorder*MAX(0,error); else if(my_infinite(lp, loB) && my_infinite(lp, upB)) ; else if(my_infinite(lp, upB)) violation[i] = sortorder*(loB - values[i]); else if(my_infinite(lp, loB)) violation[i] = sortorder*(values[i] - upB); else violation[i] = -sortorder*MAX(upB - values[i], values[i] - loB); } basisvector[i] = i; } /* Initialize user variable bound violation measures (expressed as positive values) */ for(i = 1; i <= ncols; i++) { n = nrows+i; upB = get_upbo(lp, i); loB = get_lowbo(lp, i); error = guessvector[i] - upB; if(error > -eps) violation[n] = sortorder*MAX(0,error); else { error = loB - values[n]; if(error > -eps) violation[n] = sortorder*MAX(0,error); else if(my_infinite(lp, loB) && my_infinite(lp, upB)) ; else if(my_infinite(lp, upB)) violation[n] = sortorder*(loB - values[n]); else if(my_infinite(lp, loB)) violation[n] = sortorder*(values[n] - upB); else violation[n] = -sortorder*MAX(upB - values[n], values[n] - loB); } basisvector[n] = n; } /* Sort decending by violation; this means that variables with the largest violations will be designated as basic */ sortByREAL(basisvector, violation, lp->sum, 1, FALSE); error = violation[1]; /* Adjust the non-basic indeces for the (proximal) bound state */ for(i = nrows+1, rownr = basisvector+i; i <= lp->sum; i++, rownr++) { if(*rownr <= nrows) { values[*rownr] -= lp->orig_rhs[*rownr]; if(values[*rownr] <= eps) *rownr = -(*rownr); } else if(values[i] <= get_lowbo(lp, (*rownr)-nrows)+eps) *rownr = -(*rownr); } /* Let us check for obvious row singularities and try to fix these; First assemble necessary basis statistics... */ isnz = (MYBOOL *) values; MEMCLEAR(isnz, nrows+1); slkpos = (int *) violation; MEMCLEAR(slkpos, nrows+1); for(i = 1; i <= nrows; i++) { j = abs(basisvector[i]); if(j <= nrows) { isnz[j] = TRUE; slkpos[j] = i; } else { j-= nrows; jj = mat->col_end[j-1]; isnz[COL_MAT_ROWNR(jj)] = TRUE; /* if(++jj < mat->col_end[j]) isnz[COL_MAT_ROWNR(jj)] = TRUE; */ } } for(; i <= lp->sum; i++) { j = abs(basisvector[i]); if(j <= nrows) slkpos[j] = i; } /* ...then set the corresponding slacks basic for row rank deficient positions */ for(j = 1; j <= nrows; j++) { #ifdef Paranoia if(slkpos[j] == 0) report(lp, SEVERE, "guess_basis: Internal error"); #endif if(!isnz[j]) { isnz[j] = TRUE; i = slkpos[j]; swapINT(&basisvector[i], &basisvector[j]); basisvector[j] = abs(basisvector[j]); } } /* Lastly normalize all basic variables to be coded as lower-bounded */ for(i = 1; i <= nrows; i++) basisvector[i] = -abs(basisvector[i]); /* Clean up and return status */ status = (MYBOOL) (error <= eps); Finish: FREE(values); FREE(violation); return( status ); } #endif MYBOOL __WINAPI guess_basis(lprec *lp, REAL *guessvector, int *basisvector) { MYBOOL *isnz = NULL, status = FALSE; REAL *values = NULL, *violation = NULL, eps = lp->epsprimal, *value, error, upB, loB, sortorder = -1.0; int i, j, jj, n, *rownr, *colnr, *slkpos = NULL, nrows = lp->rows, ncols = lp->columns, nsum = lp->sum; int *basisnr; MATrec *mat = lp->matA; if(!mat_validate(mat)) return( status ); /* Create helper arrays, providing for multiple use of the violation array */ if(!allocREAL(lp, &values, nsum+1, TRUE) || !allocREAL(lp, &violation, nsum+1, TRUE)) goto Finish; /* Compute the values of the constraints for the given guess vector */ i = 0; n = get_nonzeros(lp); rownr = &COL_MAT_ROWNR(i); colnr = &COL_MAT_COLNR(i); value = &COL_MAT_VALUE(i); for(; i < n; i++, rownr += matRowColStep, colnr += matRowColStep, value += matValueStep) values[*rownr] += unscaled_mat(lp, my_chsign(is_chsign(lp, *rownr), *value), *rownr, *colnr) * guessvector[*colnr]; MEMMOVE(values+nrows+1, guessvector+1, ncols); /* Initialize bound "violation" or primal non-degeneracy measures, expressed as the absolute value of the differences from the closest bound. */ for(i = 1; i <= nsum; i++) { if(i <= nrows) { loB = get_rh_lower(lp, i); upB = get_rh_upper(lp, i); } else { loB = get_lowbo(lp, i-nrows); upB = get_upbo(lp, i-nrows); } /* Free constraints/variables */ if(my_infinite(lp, loB) && my_infinite(lp, upB)) error = 0; /* Violated constraints/variable bounds */ else if(values[i]+eps < loB) error = loB-values[i]; else if(values[i]-eps > upB) error = values[i]-upB; /* Non-violated constraints/variables bounds */ else if(my_infinite(lp, upB)) error = MAX(0, values[i]-loB); else if(my_infinite(lp, loB)) error = MAX(0, upB-values[i]); else error = MIN(upB-values[i], values[i]-loB); /* MAX(upB-values[i], values[i]-loB); */ if(error != 0) violation[i] = sortorder*error; basisvector[i] = i; } /* Sort decending , meaning that variables with the largest "violations" will be designated basic. Effectively, we are performing a greedy type algorithm, but start at the "least interesting" end. */ sortByREAL(basisvector, violation, nsum, 1, FALSE); error = violation[1]; /* Used for setting the return value */ /* Let us check for obvious row singularities and try to fix these. Note that we reuse the memory allocated to the violation array. First assemble necessary basis statistics... */ slkpos = (int *) violation; n = nrows+1; MEMCLEAR(slkpos, n); isnz = (MYBOOL *) (slkpos+n+1); MEMCLEAR(isnz, n); for(i = 1; i <= nrows; i++) { j = abs(basisvector[i]); if(j <= nrows) { isnz[j] = TRUE; slkpos[j] = i; } else { j-= nrows; jj = mat->col_end[j-1]; jj = COL_MAT_ROWNR(jj); isnz[jj] = TRUE; } } for(; i <= nsum; i++) { j = abs(basisvector[i]); if(j <= nrows) slkpos[j] = i; } /* ...then set the corresponding slacks basic for row rank deficient positions */ for(j = 1; j <= nrows; j++) { if(slkpos[j] == 0) report(lp, SEVERE, "guess_basis: Internal error"); if(!isnz[j]) { isnz[j] = TRUE; i = slkpos[j]; swapINT(&basisvector[i], &basisvector[j]); basisvector[j] = abs(basisvector[j]); } } /* Adjust the non-basic indeces for the (proximal) bound state */ for(i = nrows+1, basisnr = basisvector+i; i <= nsum; i++, basisnr++) { n = *basisnr; if(n <= nrows) { values[n] -= get_rh_lower(lp, n); if(values[n] <= eps) *basisnr = -(*basisnr); } else if(values[n]-eps <= get_lowbo(lp, n-nrows)) *basisnr = -(*basisnr); } /* Lastly normalize all basic variables to be coded as lower-bounded, or effectively zero-based in the case of free variables. */ for(i = 1; i <= nrows; i++) basisvector[i] = -abs(basisvector[i]); /* Clean up and return status */ status = (MYBOOL) (error <= eps); Finish: FREE(values); FREE(violation); return( status ); }