/* Report the traditional tableau corresponding to the current basis */ MYBOOL REPORT_tableau(lprec *lp) { int j, row_nr, *coltarget; LPSREAL *prow = NULL; FILE *stream = lp->outstream; if(lp->outstream == NULL) return(FALSE); if(!lp->model_is_valid || !has_BFP(lp) || (get_total_iter(lp) == 0) || (lp->spx_status == NOTRUN)) { lp->spx_status = NOTRUN; return(FALSE); } if(!allocREAL(lp, &prow,lp->sum + 1, TRUE)) { lp->spx_status = NOMEMORY; return(FALSE); } fprintf(stream, "\n"); fprintf(stream, "Tableau at iter %.0f:\n", (double) get_total_iter(lp)); for(j = 1; j <= lp->sum; j++) if (!lp->is_basic[j]) fprintf(stream, "%15d", (j <= lp->rows ? (j + lp->columns) * ((lp->orig_upbo[j] == 0) || (is_chsign(lp, j)) ? 1 : -1) : j - lp->rows) * (lp->is_lower[j] ? 1 : -1)); fprintf(stream, "\n"); coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->columns+1, sizeof(*coltarget)); if(!get_colIndexA(lp, SCAN_USERVARS+USE_NONBASICVARS, coltarget, FALSE)) { mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE); return(FALSE); } for(row_nr = 1; (row_nr <= lp->rows + 1); row_nr++) { if (row_nr <= lp->rows) fprintf(stream, "%3d", (lp->var_basic[row_nr] <= lp->rows ? (lp->var_basic[row_nr] + lp->columns) * ((lp->orig_upbo[lp->var_basic [row_nr]] == 0) || (is_chsign(lp, lp->var_basic[row_nr])) ? 1 : -1) : lp->var_basic[row_nr] - lp->rows) * (lp->is_lower[lp->var_basic [row_nr]] ? 1 : -1)); else fprintf(stream, " "); bsolve(lp, row_nr <= lp->rows ? row_nr : 0, prow, NULL, lp->epsmachine*DOUBLEROUND, 1.0); prod_xA(lp, coltarget, prow, NULL, lp->epsmachine, 1.0, prow, NULL, MAT_ROUNDDEFAULT); for(j = 1; j <= lp->rows + lp->columns; j++) if (!lp->is_basic[j]) fprintf(stream, "%15.7f", prow[j] * (lp->is_lower[j] ? 1 : -1) * (row_nr <= lp->rows ? 1 : -1)); fprintf(stream, "%15.7f", lp->rhs[row_nr <= lp->rows ? row_nr : 0] * (double) ((row_nr <= lp->rows) || (is_maxim(lp)) ? 1 : -1)); fprintf(stream, "\n"); } fflush(stream); mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE); FREE(prow); return(TRUE); }
STATIC void updatePricer(lprec *lp, int rownr, int colnr, REAL *pcol, REAL *prow, int *nzprow) { REAL *vEdge = NULL, cEdge, hold, *newEdge, *w = NULL; int i, m, n, exitcol, errlevel = DETAILED; MYBOOL forceRefresh = FALSE, isDual, isDEVEX; if(!applyPricer(lp)) return; /* Make sure we have something to update */ hold = lp->edgeVector[0]; if(hold < 0) return; isDual = (MYBOOL) (hold > 0); /* Do common initializations and computations */ m = lp->rows; n = lp->sum; isDEVEX = is_piv_rule(lp, PRICER_DEVEX); exitcol = lp->var_basic[rownr]; /* Solve/copy Bw = a */ /* formWeights(lp, colnr, NULL, &w); Experimental */ formWeights(lp, colnr, pcol, &w); /* Price norms for the dual simplex - the basic columns */ if(isDual) { REAL rw; int targetcol; /* Don't need to compute cross-products with DEVEX */ if(!isDEVEX) { allocREAL(lp, &vEdge, m+1, FALSE); /* Extract the row of the inverse containing the leaving variable and then form the dot products against the other variables, i.e. "Tau" */ #if 0 /* Extract row explicitly */ bsolve(lp, rownr, vEdge, 0, 0.0); #else /* Reuse previously extracted row data */ MEMCOPY(vEdge, prow, m+1); vEdge[0] = 0; #endif lp->bfp_ftran_normal(lp, vEdge, NULL); } /* Deal with the variable entering the basis to become a new leaving candidate */ cEdge = lp->edgeVector[exitcol]; rw = w[rownr]; hold = 1 / rw; lp->edgeVector[colnr] = (hold*hold) * cEdge; /* Possibly adjust initial value in case of Devex */ if(isDEVEX && !DEVEX_ENHANCED && (lp->edgeVector[colnr] < DEVEX_MINVALUE)) lp->edgeVector[colnr] = DEVEX_MINVALUE; #ifdef Paranoia if(lp->edgeVector[colnr] <= lp->epsmachine) report(lp, errlevel, "updatePricer: Invalid dual norm %g at entering index %d - iteration %d\n", lp->edgeVector[colnr], rownr, lp->total_iter+lp->current_iter); #endif /* Then loop over all basic variables, but skip the leaving row */ for(i = 1; i <= m; i++) { if(i == rownr) continue; targetcol = lp->var_basic[i]; hold = w[i]; if(hold == 0) continue; hold /= rw; if(fabs(hold) < lp->epsmachine) continue; newEdge = &(lp->edgeVector[targetcol]); *newEdge += (hold*hold) * cEdge; if(isDEVEX) { if((*newEdge) > DEVEX_RESTARTLIMIT) { forceRefresh = TRUE; break; } } else { *newEdge -= 2*hold*vEdge[i]; #ifdef xxApplySteepestEdgeMinimum *newEdge = my_max(*newEdge, hold*hold+1); /* Kludge; use the primal lower bound */ #else if(*newEdge <= 0) { report(lp, errlevel, "updatePricer: Invalid dual norm %g at index %d - iteration %d\n", *newEdge, i, lp->total_iter+lp->current_iter); forceRefresh = TRUE; break; } #endif } } } /* Price norms for the primal simplex - the non-basic columns */ else { REAL *vTemp, *vAlpha, cAlpha; int *coltarget; allocREAL(lp, &vTemp, m+1, TRUE); allocREAL(lp, &vAlpha, n+1, TRUE); /* Check if we have strategy fallback for the primal */ if(!isDEVEX) isDEVEX = is_piv_mode(lp, PRICE_PRIMALFALLBACK); /* Initialize column target array */ coltarget = (int *) mempool_obtainVector(lp->workarrays, lp->sum+1, sizeof(*coltarget)); if(!get_colIndexA(lp, SCAN_ALLVARS+USE_NONBASICVARS, coltarget, FALSE)) { mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE); return; } /* Don't need to compute cross-products with DEVEX */ if(!isDEVEX) { vEdge = (REAL *) calloc((n + 1), sizeof(*vEdge)); /* Compute v and then N'v */ MEMCOPY(vTemp, w, m+1); bsolve(lp, -1, vTemp, NULL, lp->epsmachine*DOUBLEROUND, 0.0); vTemp[0] = 0; prod_xA(lp, coltarget, vTemp, NULL, XRESULT_FREE, lp->epsmachine, 0.0, vEdge, NULL); } /* Compute Sigma and then Alpha */ bsolve(lp, rownr, vTemp, NULL, 0*DOUBLEROUND, 0.0); vTemp[0] = 0; prod_xA(lp, coltarget, vTemp, NULL, XRESULT_FREE, lp->epsmachine, 0.0, vAlpha, NULL); mempool_releaseVector(lp->workarrays, (char *) coltarget, FALSE); /* Update the squared steepest edge norms; first store some constants */ cEdge = lp->edgeVector[colnr]; cAlpha = vAlpha[colnr]; /* Deal with the variable leaving the basis to become a new entry candidate */ hold = 1 / cAlpha; lp->edgeVector[exitcol] = (hold*hold) * cEdge; /* Possibly adjust initial value in case of Devex */ if(isDEVEX && !DEVEX_ENHANCED && (lp->edgeVector[exitcol] < DEVEX_MINVALUE)) lp->edgeVector[exitcol] = DEVEX_MINVALUE; #ifdef Paranoia if(lp->edgeVector[exitcol] <= lp->epsmachine) report(lp, errlevel, "updatePricer: Invalid primal norm %g at leaving index %d - iteration %d\n", lp->edgeVector[exitcol], exitcol, lp->total_iter+lp->current_iter); #endif /* Then loop over all non-basic variables, but skip the entering column */ for(i = 1; i <= lp->sum; i++) { if(lp->is_basic[i] || (i == colnr)) continue; hold = vAlpha[i]; if(hold == 0) continue; hold /= cAlpha; if(fabs(hold) < lp->epsmachine) continue; newEdge = &(lp->edgeVector[i]); *newEdge += (hold*hold) * cEdge; if(isDEVEX) { if((*newEdge) > DEVEX_RESTARTLIMIT) { forceRefresh = TRUE; break; } } else { *newEdge -= 2*hold*vEdge[i]; #ifdef ApplySteepestEdgeMinimum *newEdge = my_max(*newEdge, hold*hold+1); #else if(*newEdge < 0) { report(lp, errlevel, "updatePricer: Invalid primal norm %g at index %d - iteration %d\n", *newEdge, i, lp->total_iter+lp->current_iter); if(lp->spx_trace) report(lp, errlevel, "Error detail: (RelAlpha=%g, vEdge=%g, cEdge=%g)\n", hold, vEdge[i], cEdge); forceRefresh = TRUE; break; } #endif } } FREE(vAlpha); FREE(vTemp); } if(vEdge != NULL) FREE(vEdge); freeWeights(w); if(forceRefresh) restartPricer(lp, AUTOMATIC); }