STATIC int write_lprow(lprec *lp, int rowno, void *userhandle, write_modeldata_func write_modeldata, int maxlen) { int i, ie, j, nchars; REAL a; MATrec *mat = lp->matA; MYBOOL first = TRUE, elements; if(rowno == 0) { i = 1; ie = lp->columns+1; } else { i = mat->row_end[rowno-1]; ie = mat->row_end[rowno]; } elements = ie - i; if(write_modeldata != NULL) { nchars = 0; for(; i < ie; i++) { if(rowno == 0) { j = i; a = get_mat(lp, 0, i); if(a == 0) continue; } else { j = ROW_MAT_COLNR(i); a = ROW_MAT_VALUE(i); a = my_chsign(is_chsign(lp, rowno), a); a = unscaled_mat(lp, a, rowno, j); } if(is_splitvar(lp, j)) continue; if(!first) nchars += write_data(userhandle, write_modeldata, " "); else first = FALSE; if(a == -1) nchars += write_data(userhandle, write_modeldata, "-"); else if(a == 1) nchars += write_data(userhandle, write_modeldata, "+"); else nchars += write_data(userhandle, write_modeldata, "%+.12g ", (double)a); nchars += write_data(userhandle, write_modeldata, "%s", get_col_name(lp, j)); /* Check if we should add a linefeed */ if((maxlen > 0) && (nchars >= maxlen) && (i < ie-1)) { write_data(userhandle, write_modeldata, "%s", "\n"); nchars = 0; } } } return(elements); }
/* List the current user data matrix columns over the selected row range */ void blockWriteAMAT(FILE *output, const char *label, lprec* lp, int first, int last) { int i, j, k = 0; int nzb, nze, jb; double hold; MATrec *mat = lp->matA; if(!mat_validate(mat)) return; if(first < 0) first = 0; if(last < 0) last = lp->rows; fprintf(output, "%s", label); fprintf(output, "\n"); if(first == 0) { for(j = 1; j <= lp->columns; j++) { hold = get_mat(lp, 0, j); fprintf(output, " %18g", hold); k++; if(my_mod(k, 4) == 0) { fprintf(output, "\n"); k = 0; } } if(my_mod(k, 4) != 0) { fprintf(output, "\n"); k = 0; } first++; } nze = mat->row_end[first-1]; for(i = first; i <= last; i++) { nzb = nze; nze = mat->row_end[i]; if(nzb >= nze) jb = lp->columns+1; else jb = ROW_MAT_COLNR(nzb); for(j = 1; j <= lp->columns; j++) { if(j < jb) hold = 0; else { hold = get_mat(lp, i, j); nzb++; if(nzb < nze) jb = ROW_MAT_COLNR(nzb); else jb = lp->columns+1; } fprintf(output, " %18g", hold); k++; if(my_mod(k, 4) == 0) { fprintf(output, "\n"); k = 0; } } if(my_mod(k, 4) != 0) { fprintf(output, "\n"); k = 0; } } if(my_mod(k, 4) != 0) fprintf(output, "\n"); }
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 ); }
int CurtisReidScales(lprec *lp, MYBOOL _Advanced, REAL *FRowScale, REAL *FColScale) { int i, row, col, ent, nz; REAL *RowScalem2, *ColScalem2, *RowSum, *ColSum, *residual_even, *residual_odd; REAL sk, qk, ek, skm1, qkm1, ekm1, qkm2, qkqkm1, ekm2, ekekm1, absvalue, logvalue, StopTolerance; int *RowCount, *ColCount, colMax; int Result; MATrec *mat = lp->matA; REAL *value; int *rownr, *colnr; if(CurtisReidMeasure(lp, _Advanced, FRowScale, FColScale)<0.1*get_nonzeros(lp)) return(0); /* Allocate temporary memory and find RowSum and ColSum measures */ nz = get_nonzeros(lp); colMax = lp->columns; allocREAL(lp, &RowSum, lp->rows+1, TRUE); allocINT(lp, &RowCount, lp->rows+1, TRUE); allocREAL(lp, &residual_odd, lp->rows+1, TRUE); allocREAL(lp, &ColSum, colMax+1, TRUE); allocINT(lp, &ColCount, colMax+1, TRUE); allocREAL(lp, &residual_even, colMax+1, TRUE); allocREAL(lp, &RowScalem2, lp->rows+1, FALSE); allocREAL(lp, &ColScalem2, colMax+1, FALSE); /* Set origin for row scaling */ for(i = 1; i <= colMax; i++) { absvalue=fabs(lp->orig_obj[i]); if(absvalue>0) { logvalue = log(absvalue); ColSum[i] += logvalue; RowSum[0] += logvalue; ColCount[i]++; RowCount[0]++; } } value = &(COL_MAT_VALUE(0)); rownr = &(COL_MAT_ROWNR(0)); colnr = &(COL_MAT_COLNR(0)); for(i = 0; i < nz; i++, value += matValueStep, rownr += matRowColStep, colnr += matRowColStep) { absvalue=fabs(*value); if(absvalue>0) { logvalue = log(absvalue); ColSum[*colnr] += logvalue; RowSum[*rownr] += logvalue; ColCount[*colnr]++; RowCount[*rownr]++; } } /* Make sure we dont't have division by zero errors */ for(row = 0; row <= lp->rows; row++) if(RowCount[row] == 0) RowCount[row] = 1; for(col = 1; col <= colMax; col++) if(ColCount[col] == 0) ColCount[col] = 1; /* Initialize to RowScale = RowCount-1 RowSum ColScale = 0.0 residual = ColSum - ET RowCount-1 RowSum */ StopTolerance= MAX(lp->scalelimit-floor(lp->scalelimit), DEF_SCALINGEPS); StopTolerance *= (REAL) nz; for(row = 0; row <= lp->rows; row++) { FRowScale[row] = RowSum[row] / (REAL) RowCount[row]; RowScalem2[row] = FRowScale[row]; } /* Compute initial residual */ for(col = 1; col <= colMax; col++) { FColScale[col] = 0; ColScalem2[col] = 0; residual_even[col] = ColSum[col]; if(lp->orig_obj[col] != 0) residual_even[col] -= RowSum[0] / (REAL) RowCount[0]; i = mat->col_end[col-1]; rownr = &(COL_MAT_ROWNR(i)); ent = mat->col_end[col]; for(; i < ent; i++, rownr += matRowColStep) { residual_even[col] -= RowSum[*rownr] / (REAL) RowCount[*rownr]; } } /* Compute sk */ sk = 0; skm1 = 0; for(col = 1; col <= colMax; col++) sk += (residual_even[col]*residual_even[col]) / (REAL) ColCount[col]; Result = 0; qk=1; qkm1=0; qkm2=0; ek=0; ekm1=0; ekm2=0; while(sk>StopTolerance) { /* Given the values of residual and sk, construct ColScale (when pass is even) RowScale (when pass is odd) */ qkqkm1 = qk * qkm1; ekekm1 = ek * ekm1; if((Result % 2) == 0) { /* pass is even; construct RowScale[pass+1] */ if(Result != 0) { for(row = 0; row <= lp->rows; row++) RowScalem2[row] = FRowScale[row]; if(qkqkm1 != 0) { for(row = 0; row <= lp->rows; row++) FRowScale[row]*=(1 + ekekm1 / qkqkm1); for(row = 0; row<=lp->rows; row++) FRowScale[row]+=(residual_odd[row] / (qkqkm1 * (REAL) RowCount[row]) - RowScalem2[row] * ekekm1 / qkqkm1); } } } else { /* pass is odd; construct ColScale[pass+1] */ for(col = 1; col <= colMax; col++) ColScalem2[col] = FColScale[col]; if(qkqkm1 != 0) { for(col = 1; col <= colMax; col++) FColScale[col] *= (1 + ekekm1 / qkqkm1); for(col = 1; col <= colMax; col++) FColScale[col] += (residual_even[col] / ((REAL) ColCount[col] * qkqkm1) - ColScalem2[col] * ekekm1 / qkqkm1); } } /* update residual and sk (pass + 1) */ if((Result % 2) == 0) { /* even */ /* residual */ for(row = 0; row <= lp->rows; row++) residual_odd[row] *= ek; for(i = 1; i <= colMax; i++) if(lp->orig_obj[i] != 0) residual_odd[0] += (residual_even[i] / (REAL) ColCount[i]); rownr = &(COL_MAT_ROWNR(0)); colnr = &(COL_MAT_COLNR(0)); for(i = 0; i < nz; i++, rownr += matRowColStep, colnr += matRowColStep) { residual_odd[*rownr] += (residual_even[*colnr] / (REAL) ColCount[*colnr]); } for(row = 0; row <= lp->rows; row++) residual_odd[row] *= (-1 / qk); /* sk */ skm1 = sk; sk = 0; for(row = 0; row <= lp->rows; row++) sk += (residual_odd[row]*residual_odd[row]) / (REAL) RowCount[row]; } else { /* odd */ /* residual */ for(col = 1; col <= colMax; col++) residual_even[col] *= ek; for(i = 1; i <= colMax; i++) if(lp->orig_obj[i] != 0) residual_even[i] += (residual_odd[0] / (REAL) RowCount[0]); rownr = &(COL_MAT_ROWNR(0)); colnr = &(COL_MAT_COLNR(0)); for(i = 0; i < nz; i++, rownr += matRowColStep, colnr += matRowColStep) { residual_even[*colnr] += (residual_odd[*rownr] / (REAL) RowCount[*rownr]); } for(col = 1; col <= colMax; col++) residual_even[col] *= (-1 / qk); /* sk */ skm1 = sk; sk = 0; for(col = 1; col <= colMax; col++) sk += (residual_even[col]*residual_even[col]) / (REAL) ColCount[col]; } /* Compute ek and qk */ ekm2=ekm1; ekm1=ek; ek=qk * sk / skm1; qkm2=qkm1; qkm1=qk; qk=1-ek; Result++; } /* Synchronize the RowScale and ColScale vectors */ ekekm1 = ek * ekm1; if(qkm1 != 0) { if((Result % 2) == 0) { /* pass is even, compute RowScale */ for(row = 0; row<=lp->rows; row++) FRowScale[row]*=(1.0 + ekekm1 / qkm1); for(row = 0; row<=lp->rows; row++) FRowScale[row]+=(residual_odd[row] / (qkm1 * (REAL) RowCount[row]) - RowScalem2[row] * ekekm1 / qkm1); } else { /* pass is odd, compute ColScale */ for(col=1; col<=colMax; col++) FColScale[col]*=(1 + ekekm1 / qkm1); for(col=1; col<=colMax; col++) FColScale[col]+=(residual_even[col] / ((REAL) ColCount[col] * qkm1) - ColScalem2[col] * ekekm1 / qkm1); } } /* Do validation, if indicated */ if(FALSE && mat_validate(mat)){ double check, error; /* CHECK: M RowScale + E ColScale = RowSum */ error = 0; for(row = 0; row <= lp->rows; row++) { check = (REAL) RowCount[row] * FRowScale[row]; if(row == 0) { for(i = 1; i <= colMax; i++) { if(lp->orig_obj[i] != 0) check += FColScale[i]; } } else { i = mat->row_end[row-1]; ent = mat->row_end[row]; for(; i < ent; i++) { col = ROW_MAT_COLNR(i); check += FColScale[col]; } } check -= RowSum[row]; error += check*check; } /* CHECK: E^T RowScale + N ColScale = ColSum */ error = 0; for(col = 1; col <= colMax; col++) { check = (REAL) ColCount[col] * FColScale[col]; if(lp->orig_obj[col] != 0) check += FRowScale[0]; i = mat->col_end[col-1]; ent = mat->col_end[col]; rownr = &(COL_MAT_ROWNR(i)); for(; i < ent; i++, rownr += matRowColStep) { check += FRowScale[*rownr]; } check -= ColSum[col]; error += check*check; } } /* Convert to scaling factors (rounding to nearest power of 2 can optionally be done as a separate step later) */ for(col = 1; col <= colMax; col++) { absvalue = exp(-FColScale[col]); if(absvalue < MIN_SCALAR) absvalue = MIN_SCALAR; if(absvalue > MAX_SCALAR) absvalue = MAX_SCALAR; if(!is_int(lp,col) || is_integerscaling(lp)) FColScale[col] = absvalue; else FColScale[col] = 1; } for(row = 0; row <= lp->rows; row++) { absvalue = exp(-FRowScale[row]); if(absvalue < MIN_SCALAR) absvalue = MIN_SCALAR; if(absvalue > MAX_SCALAR) absvalue = MAX_SCALAR; FRowScale[row] = absvalue; } /* free temporary memory */ FREE(RowSum); FREE(ColSum); FREE(RowCount); FREE(ColCount); FREE(residual_even); FREE(residual_odd); FREE(RowScalem2); FREE(ColScalem2); return(Result); }