static bool process_inactive (lpprob_struct *orig_lp, int oxkndx) /* This routine handles the data structure updates for an inactive variable x<k>. We need to have a look at the bounds l<k> and u<k>, and perhaps update the status kept in dy_origvars. We need to add the contribution c<k>l<k> or c<k>u<k> to the objective function. Finally, if we've reloaded b & blow due to a bound or rhs change, we need to walk the column a<k> and adjust b<i> (and perhaps blow<i>) for each nonzero a<ik> in the active system. Parameters: orig_lp: the original lp problem oxkndx: index of x<k> in orig_sys Returns: TRUE if the update is made without incident, FALSE otherwise. */ { int oaindx,aindx,ndx ; double xk,lk,uk,ck ; pkvec_struct *ak ; pkcoeff_struct *aik ; consys_struct *orig_sys ; flags xkstatus ; const char *rtnnme = "process_inactive" ; orig_sys = orig_lp->consys ; xkstatus = getflg(orig_lp->status[oxkndx],vstatSTATUS) ; # ifdef DYLP_PARANOIA /* Any inactive variable should be nonbasic, and the paranoid check is looking to make sure of this. */ if (!VALID_STATUS(xkstatus)) { errmsg(300,rtnnme,(int) xkstatus, consys_nme(orig_sys,'v',oxkndx,FALSE,NULL),oxkndx) ; return (FALSE) ; } if (flgoff(xkstatus,vstatNONBASIC|vstatNBFR)) { errmsg(433,rtnnme, dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, "inactive",consys_nme(orig_sys,'v',oxkndx,TRUE,NULL),oxkndx, dy_prtvstat(xkstatus)) ; return (FALSE) ; } # endif /* The bounds can change arbitrarily, and the client may not be maintaining the status vector, but we're limited in what we can do --- bounds and status are our only clues to the value of an inactive variable. (Contrast with the equivalent section in process_active.) */ lk = orig_sys->vlb[oxkndx] ; uk = orig_sys->vub[oxkndx] ; ck = orig_sys->obj[oxkndx] ; /* Start with the case that both bounds are finite. Use a previous status of NBLB or NBUB. Otherwise, guess from the sign of the objective coefficient. `Dirty' fixed variables are marked as unloadable. */ if (lk > -dy_tols->inf && uk < dy_tols->inf) { if (atbnd(lk,uk) && lk != uk) { if (flgon(xkstatus,vstatNBLB|vstatNBUB)) { setflg(xkstatus,vstatNOLOAD) ; } else { if (ck < 0) { xkstatus = vstatNBUB|vstatNOLOAD ; } else { xkstatus = vstatNBLB|vstatNOLOAD ; } } # ifndef DYLP_NDEBUG if (dy_opts->print.setup >= 3) { dyio_outfmt(dy_logchn,dy_gtxecho,"\n\tDirty fixed variable %s (%d)", consys_nme(orig_sys,'v',oxkndx,0,0),oxkndx) ; dyio_outfmt(dy_logchn,dy_gtxecho, " assigned status %s.",dy_prtvstat(xkstatus)) ; dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t original lb = %g, ub = %g, diff = %g, tol = %g", lk,uk,uk-lk,dy_tols->pfeas) ; } # endif } else if (lk == uk) { xkstatus = vstatNBFX|vstatNOLOAD ; } else if (flgon(xkstatus,vstatNBLB|vstatNBUB)) { xkstatus = orig_lp->status[oxkndx] ; } else { if (ck < 0) { xkstatus = vstatNBUB ; } else { xkstatus = vstatNBLB ; } } } /* Variables with one bound, or no bounds. No choices here. */ else if (lk > -dy_tols->inf) { xkstatus = vstatNBLB ; } else if (uk < dy_tols->inf) { xkstatus = vstatNBUB ; } else { xkstatus = vstatNBFR ; } /* Determine the variable's value and set up the status entries. The default case in the switch below should never execute, but it serves for paranoia and lets gcc conclude xk will always have a value. Consider whether it's really a good idea to change orig_lp->status. */ switch (getflg(xkstatus,vstatSTATUS)) { case vstatNBLB: case vstatNBFX: { xk = lk ; break ; } case vstatNBUB: { xk = uk ; break ; } case vstatNBFR: { xk = 0 ; break ; } default: { xk = 0 ; errmsg(1,rtnnme,__LINE__) ; return (FALSE) ; } } orig_lp->status[oxkndx] = xkstatus ; dy_origvars[oxkndx] = -((int) xkstatus) ; /* Note any contribution to the objective and constraint rhs & rhslow values. */ dy_lp->inactzcorr += xk*orig_sys->obj[oxkndx] ; if (flgon(orig_lp->ctlopts,lpctlRHSCHG|lpctlLBNDCHG|lpctlUBNDCHG)) { ak = NULL ; if (consys_getcol_pk(orig_sys,oxkndx,&ak) == FALSE) { errmsg(122,rtnnme,orig_sys->nme,"variable", consys_nme(orig_sys,'v',oxkndx,TRUE,NULL),oxkndx) ; if (ak != NULL) pkvec_free(ak) ; return (FALSE) ; } for (ndx = 0, aik = &ak->coeffs[0] ; ndx < ak->cnt ; ndx++, aik++) { oaindx = aik->ndx ; if (ACTIVE_CON(oaindx)) { aindx = dy_origcons[oaindx] ; dy_sys->rhs[aindx] -= aik->val*xk ; if (dy_sys->ctyp[aindx] == contypRNG) dy_sys->rhslow[aindx] -= aik->val*xk ; } } pkvec_free(ak) ; } /* And we're done. Print some information and return. */ # ifndef DYLP_NDEBUG if (dy_opts->print.crash >= 4) { dyio_outfmt(dy_logchn,dy_gtxecho,"\n\t %s (%d) %s inactive with value ", consys_nme(orig_sys,'v',oxkndx,FALSE,NULL),oxkndx, dy_prtvstat(xkstatus)) ; switch (getflg(xkstatus,vstatSTATUS)) { case vstatNBFX: case vstatNBLB: case vstatNBUB: case vstatNBFR: { dyio_outfmt(dy_logchn,dy_gtxecho,"%g.",xk) ; break ; } default: { dyio_outfmt(dy_logchn,dy_gtxecho,"??.") ; break ; } } } # endif return (TRUE) ; }
dyret_enum dy_factor (flags *calcflgs) /* This routine orchestrates the LU factorisation of the basis. The glpk routines do the grunt work. This routine provides the intelligence. If inv_decomp aborts the attempt to factor due to numerical instability, we tighten the pivot selection parameters one notch and try again, giving up only when no further increase is possible. The sequence of values for the pivot selection parameters are defined in a table at the top of this file. If inv_decomp aborts the attempt to factor because the basis is singular, we correct the basis with adjust_basis and take another run at factoring. In the event that the basis is successfully patched, we have serious work to do. See the comments with adjust_therest for further information. If the user has for some reason disabled basis patching, we return dyrSINGULAR. inv_decomp (actually, luf_decomp) is self-expanding --- if more space is needed to hold the factorization, the expansion is handled internally. dylp uses ladEXPAND to force basis expansion after a pivot fails due to lack of space. In glpk, inv_update will set instructions in the basis structure and luf_decomp will handle the expansion, so ladEXPAND is redundant. No action need be taken in this routine. It's also not possible to tell if the basis has been expanded, so ladEXPAND is not set on output. Parameters: calcflgs: (i) ladPRIMALS indicates the primal variables should be recalculated after factoring the basis. ladDUALS indicates the dual variables should be recalculated after factoring the basis. ladEXPAND indicates that the basis should be expanded prior to refactoring. (o) flags are set to indicate if the corresponding variables have been recalculated. Returns: dyrOK if the basis is factored without incident dyrPATCHED if the basis was singular and has been repaired dyrSINGULAR if the basis was singular and has not been repaired dyrNUMERIC if factoring failed for the strictest pivoting regimen dyrFATAL for other fatal errors NOTE: glpinv/glpluf will crash and burn if they encounter what they consider to be a fatal error, rather than returning a fatal error code. This needs to be addressed at some point. In particular, failure to expand the basis, failure to load the basis from the constraint system, and various parameter errors fall into this category. */ { int retval,patchcnt ; bool try_again,patched ; dyret_enum retcode ; patch_struct *patches ; const char *rtnnme = "dy_factor" ; #ifdef DYLP_PARANOIA if (dy_sys == NULL) { errmsg(2,rtnnme,"dy_sys") ; return (dyrFATAL) ; } if (dy_basis == NULL) { errmsg(2,rtnnme,"basis") ; return (dyrFATAL) ; } #endif # ifdef DYLP_STATISTICS if (dy_stats != NULL) { int pivcnt ; pivcnt = dy_lp->tot.pivs-dy_stats->factor.prevpiv ; dy_stats->factor.avgpivs = dy_stats->factor.avgpivs*dy_stats->factor.cnt ; dy_stats->factor.avgpivs += pivcnt ; dy_stats->factor.cnt++ ; dy_stats->factor.avgpivs /= dy_stats->factor.cnt ; if (pivcnt > dy_stats->factor.maxpivs) dy_stats->factor.maxpivs = pivcnt ; dy_stats->factor.prevpiv = dy_lp->tot.pivs ; } # endif retcode = dyrINV ; patchcnt = 0 ; patches = NULL ; /* Call luf_adjustsize to set the actual size of the basis. If the allocated capacity is too small, it will be expanded. */ luf_adjustsize() ; /* Open a loop for factorisation attempts. We'll persist in the face of numerical stability problems as long as there's room to tighten the pivot selection. At present, glpinv/glpluf will crash and burn if they encounter fatal problems. The basis load is implicit --- the routine factor_loadcol is called from luf_decomp to load up the coefficients. */ try_again = TRUE ; patched = FALSE ; while (try_again) { retval = inv_decomp(luf_basis,dy_sys,factor_loadcol) ; # ifndef DYLP_NDEBUG if ((retval == 0 && dy_opts->print.basis >= 4) || (retval > 0 && dy_opts->print.basis >= 2)) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: factored with %s, basis stability %g.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, dy_prtpivparms(-1),luf_basis->min_vrratio) ; } # endif /* Deal with the result. A return code of 0 means there were no difficulties; 1 says the basis was singular and had to be patched before the factorisation could be completed. Either is success, and we're done. */ switch (retval) { case 0: { try_again = FALSE ; retcode = dyrOK ; break ; } /* Alas, the failures. If the problem is a singular basis (retval = 1), fix up the basis structures as indicated in the luf_basis structure and try again to factor the basis, unless the user has forbidden it. If the problem is numerical instability (retval = 2) try to make the pivot selection more stringent, and keep trying until we can try no more, at which point we'll return numeric instability to the caller. What's left is fatal confusion; pass the buck back to the caller. */ case 1: { if (dy_opts->patch == FALSE) { errmsg(308,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,dy_prtdyret(dyrSINGULAR)) ; clrflg(*calcflgs,ladPRIMALS|ladDUALS) ; return (dyrSINGULAR) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: attempting to patch singular basis.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters) ; } # endif adjust_basis(&patchcnt,&patches) ; patched = TRUE ; break ; } case 2: { retcode = dyrNUMERIC ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: factor failed at %s, numerical instability,", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, dy_prtpivparms(-1)) ; dyio_outfmt(dy_logchn,dy_gtxecho," max = %g, gro = %g.", luf_basis->luf->big_v,luf_basis->luf->max_gro) ; } # endif if (dy_setpivparms(+1,0) == FALSE) { errmsg(307,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,dy_prtpivparms(-1)) ; return (retcode) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho,"\n\ttrying again with %s.", dy_prtpivparms(-1)) ; } # endif break ; } default: { errmsg(7,rtnnme,__LINE__,"inv_decomp return code",retval) ; return (dyrFATAL) ; } } } /* If we reach here, we managed to factor the basis. Reset the count of pivots since the last refactor. If the basis was patched, we have some serious cleanup to do, so call adjust_therest to deal with the details. Otherwise, turn to the requests to calculate values for the primal and/or dual variables. */ dy_lp->basis.etas = 0 ; if (patched == TRUE) { retcode = adjust_therest(patchcnt,patches) ; FREE(patches) ; if (retcode == dyrFATAL) { errmsg(306,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters) ; return (dyrFATAL) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 1) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t[%s]: compensated for basis correction.", dy_sys->nme) ; } # endif if (!(dy_lp->phase == dyINIT)) { setflg(*calcflgs,ladPRIMALS|ladDUALS) ; if (retcode == dyrLOSTDFEAS) setflg(*calcflgs,ladDUALFEAS) ; } retcode = dyrPATCHED ; } else { if (flgon(*calcflgs,ladPRIMALS)) { if (dy_calcprimals() == FALSE) { clrflg(*calcflgs,ladPRIMALS) ; return (dyrFATAL) ; } } if (flgon(*calcflgs,ladDUALS)) dy_calcduals() ; } return (retcode) ; }
int main (int argc, char **argv) { bool errecho = TRUE ; ioid ttyin,ttyout,outchn ; const char *errmsgpath = DYLP_ERRMSGPATH ; char *errlogpath = NULL ; /* These need to be globals to keep cmdint.c::process_cmds happy. lpopts_struct *main_lpopts ; lptols_struct *main_lptols ; */ consys_struct *main_sys ; lpprob_struct *main_lp ; lpret_enum lpretval ; double z ; int errcnt,cnt ; /* Set this to TRUE if you want to see the solutions for the test lp problems. */ bool dumpsoln = TRUE ; char *rtnnme = argv[0] ; /* dy_basis.c */ extern void dy_initbasis(int concnt, int factor_freq, double zero_tol), dy_freebasis(void) ; /* dytest_problems.c */ extern consys_struct *dytest_exmip1sys(lptols_struct *tols) ; extern consys_struct *dytest_exprimalraysys(lptols_struct *tols) ; extern consys_struct *dytest_exdualraysys(lptols_struct *tols) ; extern consys_struct *dytest_galenetbndssys(lptols_struct *tols) ; extern consys_struct *dytest_galenetleqsys(lptols_struct *tols) ; extern consys_struct *dytest_galenetmixedsys(lptols_struct *tols) ; extern consys_struct *dytest_galenetsys(lptols_struct *tols) ; extern consys_struct *dytest_afirosys(lptols_struct *tols) ; extern consys_struct *dytest_boeing2sys(lptols_struct *tols) ; /* dytest_tableau.c */ extern int dytest_betaj(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_betai(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_abarj(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_abari(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; /* dytest_solutions.c */ extern int dytest_rowDuals(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_allDuals(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_colDuals(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_colPrimals(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_rowPrimals(lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; /* dytest_rays.c */ extern int dytest_primalRays(int *p_numRays,lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; extern int dytest_dualRays(int *p_numRays,lpprob_struct *lp, lptols_struct *lptols,lpopts_struct *lpopts) ; outchn = IOID_INV ; /* Execute initialization routines for the i/o and error reporting packages. */ errinit(errmsgpath,errlogpath,errecho) ; if (dyio_ioinit() != TRUE) { errmsg(1,rtnnme,__LINE__) ; exit (2) ; } /* Connect ttyout to the standard output. Initialize ttyin, setting the mode to line-oriented. Serious internal confusion if we can't manage these. Set the initial command input channel to stdin. */ ttyout = dyio_openfile("stdout","w") ; if (ttyout == IOID_INV) { errmsg(1,rtnnme,__LINE__) ; exit(3) ; } ttyin = dyio_openfile("stdin","r") ; if (ttyin == IOID_INV) { errmsg(1,rtnnme,__LINE__) ; exit(4) ; } (void) dyio_setmode(ttyin,'l') ; dy_cmdchn = ttyin ; dy_logchn = IOID_NOSTRM ; dy_cmdecho = TRUE ; dy_gtxecho = TRUE ; /* Announce we're running. */ dyio_outfmt(ttyout,dy_gtxecho,"Dylp v%s unit test start.\n",DYLP_VERSION) ; dyio_flushio(ttyout,dy_gtxecho) ; errcnt = 0 ; /* Acquire default option and tolerance structures. Allocate an lpprob_struct to be our top-level handle. */ main_lpopts = NULL ; main_lptols = NULL ; dy_defaults(&main_lpopts,&main_lptols) ; main_lp = (lpprob_struct *) CALLOC(1,sizeof(lpprob_struct)) ; /* Initialise the basis factorisation package with a data structure capable of 50 constraints. The second parameter controls how many basis updates the basis can hold before it requires refactoring. Adding 5 to dylp's refactor interval should give a safety margin. */ dy_initbasis(50,main_lpopts->factor+5,0.0) ; #if RUN_EXMIP1 > 0 /* Load the exmip1 example and see if we can solve it. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading exmip1 example from static data.\n") ; main_sys = dytest_exmip1sys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load exmip1 constraint system.\n") ; errcnt++ ; } /* Check over the option settings, now that we know how big the constraint system will be. */ else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; /* Initialise the main_lp structure to pass the problem in to dylp. * We need to retain the data structures (NOFREE) so that we can consult them when dylp returns. * The phase needs to be dyINV at the start. * We need to specify the constraint system, and its size. * Let dylp work with a partial system and purge at the end. This stresses the routines we're testing; they need to synthesize parts of the values they return. * The remaining options specify an all-logical basis, allow scaling, and force a cold start. */ setflg(main_lp->ctlopts,lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = FALSE ; main_lpopts->finpurge.vars = TRUE ; main_lpopts->finpurge.cons = TRUE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 0 ; main_lpopts->forcecold = TRUE ; /* main_lpopts->print.major = 1 ; main_lpopts->print.scaling = 1 ; main_lpopts->print.setup = 6 ; main_lpopts->print.crash = 3 ; main_lpopts->print.conmgmt = 3 ; main_lpopts->print.varmgmt = 3 ; main_lpopts->print.soln = 3 ; */ /* Solve. */ dyio_outfmt(ttyout,dy_gtxecho,"Solving exmip1 ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; /* And the result is ... */ dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 3.236842105263 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test the tableau, solution, and ray routines. The tests are predominantly mathematical identities, with a bit of data structure consistency thrown in for good measure. Completely problem-independent. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; /* Call dylp to free internal structures, then free main_sys. */ comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_AFIRO > 0 /* Let's try another. Load and solve afiro. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading afiro example from static data.\n") ; main_sys = dytest_afirosys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load afiro constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = FALSE ; main_lpopts->finpurge.vars = TRUE ; main_lpopts->finpurge.cons = TRUE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; dyio_outfmt(ttyout,dy_gtxecho,"Solving afiro ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = -464.753142857143 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_BOEING2 > 0 /* Let's try another. Load and solve boeing2. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading boeing2 example from static data.\n") ; main_sys = dytest_boeing2sys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load boeing2 constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = FALSE ; main_lpopts->finpurge.vars = TRUE ; main_lpopts->finpurge.cons = TRUE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; main_lpopts->print.phase2 = 0 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving boeing2 ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = -315.0187280152 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_EXPRIMALRAY > 0 /* Let's try another. Load and solve exprimalray. The polyhedron for exprimalray is carefully crafted to provide an initial bounded optimum point with two rays that are exposed by the proper change in objective. Force dylp to use the full system for this test and do not allow final purging, lest we miss the point and rays we're aiming for. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading exprimalray example from static data.\n") ; main_sys = dytest_exprimalraysys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load exprimalray constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; dyio_outfmt(ttyout,dy_gtxecho,"Solving exprimalray ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = -21 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Now tweak the objective to 3x1+x2+x3, giving us two rays. Solve, then test that we have valid primal rays. First ask for just one, then ask for five, expecting two. */ main_sys->obj[1] = -1.0 ; main_sys->obj[2] = -4.0 ; setflg(main_lp->ctlopts,lpctlOBJCHG) ; main_lpopts->forcecold = FALSE ; dyio_outfmt(dy_logchn,dy_gtxecho,"Resolving exprimalray ...") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } cnt = 1 ; errcnt += dytest_primalRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d primal rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_primalRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 2) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d primal rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes unbounded. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_EXDUALRAY > 0 /* Let's try another. Load and solve exdualray. Exdualray takes advantage of duality: The dual polyhedron is exactly the primal polyhedron of the previous problem. The symmetry should be clear from the output (objective, dual, and primal values are negated, but otherwise identical) */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading exdualray example from static data.\n") ; main_sys = dytest_exdualraysys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load exdualray constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.phase2 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving exdualray ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 21 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Tweak the rhs to (-1)*(-1 -4 1) to produce a pair of rays in the dual. */ main_sys->rhs[2] = 4.0 ; setflg(main_lp->ctlopts,lpctlRHSCHG) ; main_lpopts->forcecold = FALSE ; main_lpopts->print.force = 1 ; dyio_outfmt(dy_logchn,dy_gtxecho,"Resolving exdualray ...") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test that we have valid dual rays. First ask for just one, then ask for five, expecting two. */ errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; cnt = 1 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 2) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes infeasible. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_GALENETBNDS > 0 /* Now a sequence of three problems based on galenet that really exercise the dual ray code. Galenet is a straightforward primal infeasible / dual unbounded problem. The objective is identically zero, so it's a pure feasibility problem. The objective returned from dylp will be z = 48, the amount of primal infeasibility. The first version is galenetbnds. All equalities from galenet are converted to inequalities, all implicit bounds are converted to explicit bound constraints, and then all >= constraints are converted to <= constraints. This is the simplest possible case for returning dual rays. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading galenetbnds example from static data.\n") ; main_sys = dytest_galenetbndssys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load galenetbnds constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.phase2 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving galenetbnds ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 48.0 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } dumpsoln = TRUE ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test that we have valid dual rays. First ask for just one, then ask for five, expecting three. */ cnt = 1 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 3) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes infeasible. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_GALENETLEQ > 0 /* Now load and solve galenetleq --- galenetbnds, but the bound constraints on variables are now handled in the usual manner, as implicit bounds. We'll need the full ray (explicit duals y = c<B>inv(B) as well as duals associated with nonbasic bounded variables) in order to pass the mathematical tests rb < 0, rA > 0. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading galenetleq example from static data.\n") ; main_sys = dytest_galenetleqsys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load galenetleq constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.phase2 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving galenetleq ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 48.0 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } dumpsoln = TRUE ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test that we have valid dual rays. First ask for just one, then ask for five, expecting three. */ cnt = 1 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 3) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes infeasible. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_GALENETMIXED > 0 /* Now load and solve galenetmixed --- bound constraints on variables are handled implicitly, and the constraint system is a mix of <= and >= constraints (the equalities are handled as a pair of inequalities). As with galenetleq, we'll need the full ray (explicit duals y = c<B>inv(B) as well as duals associated with nonbasic bounded variables) in order to pass the mathematical tests rb < 0, rA > 0. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading galenetmixed example from static data.\n") ; main_sys = dytest_galenetmixedsys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load galenetmixed constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.phase2 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving galenetmixed ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 48.0 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } dumpsoln = TRUE ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test that we have valid dual rays. First ask for just one, then ask for five, expecting three. */ cnt = 1 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 3) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes infeasible. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif #if RUN_GALENET > 0 /* Now load and solve the original galenet --- bound constraints on variables are handled implicitly, and the constraint system is a mix of <=, =, and >= constraints. As with galenetleq, we'll need the full ray (explicit duals y = c<B>inv(B) as well as duals associated with nonbasic bounded variables) in order to pass the mathematical tests rb < 0, rA > 0. */ dyio_outfmt(ttyout,dy_gtxecho, "\n\nLoading galenet example from static data.\n") ; main_sys = dytest_galenetsys(main_lptols) ; if (main_sys == NULL) { dyio_outfmt(ttyout,dy_gtxecho, "Failed to load galenet constraint system.\n") ; errcnt++ ; } else { dy_checkdefaults(main_sys,main_lpopts,main_lptols) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; main_lp->phase = dyINV ; main_lp->consys = main_sys ; main_lp->rowsze = main_sys->rowsze ; main_lp->colsze = main_sys->colsze ; main_lpopts->forcecold = TRUE ; main_lpopts->fullsys = TRUE ; main_lpopts->finpurge.vars = FALSE ; main_lpopts->finpurge.cons = FALSE ; main_lpopts->coldbasis = ibLOGICAL ; main_lpopts->scaling = 2 ; /* main_lpopts->print.major = 1 ; main_lpopts->print.phase1 = 4 ; main_lpopts->print.phase2 = 4 ; main_lpopts->print.dual = 4 ; main_lpopts->print.tableau = 4 ; main_lpopts->print.soln = 3 ; main_lpopts->print.rays = 5 ; */ dyio_outfmt(ttyout,dy_gtxecho,"Solving galenet ... ") ; lpretval = do_lp(main_lp,main_lptols,main_lpopts,1) ; dyio_outfmt(ttyout,dy_gtxecho,"\n %s, z = %.12f.\n", dy_prtlpret(lpretval),main_lp->obj) ; z = 46.0 ; if (!(fabs(main_lp->obj-z) <= main_lptols->cost)) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: z = %g, expected %g, error %g, tol %g.\n", main_lp->obj,z,fabs(main_lp->obj-z),main_lptols->cost) ; } dumpsoln = TRUE ; if (dumpsoln == TRUE) { dy_dumpcompact(dy_logchn,dy_gtxecho,main_lp,FALSE) ; } /* Test that we have valid dual rays. First ask for just one, then ask for five, expecting two. Note that we end up at a different vertex than the previous expanded versions of galenet. */ cnt = 1 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 1) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,1) ; } cnt = 5 ; errcnt += dytest_dualRays(&cnt,main_lp,main_lptols,main_lpopts) ; if (cnt != 2) { errcnt++ ; dyio_outfmt(ttyout,dy_gtxecho, " ERROR: %d dual rays returned, expected %d.\n", cnt,2) ; } /* Run the remainder of the tests, to make sure they run without error when dylp finishes infeasible. */ errcnt += dytest_betaj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abarj(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_betai(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_abari(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_allDuals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_colPrimals(main_lp,main_lptols,main_lpopts) ; errcnt += dytest_rowPrimals(main_lp,main_lptols,main_lpopts) ; comflg(main_lp->ctlopts,lpctlONLYFREE|lpctlNOFREE) ; dylp(main_lp,main_lpopts,main_lptols,NULL) ; consys_free(main_sys) ; main_sys = NULL ; main_lp->consys = NULL ; dy_freesoln(main_lp) ; } #endif /* Report the result before we shut down. */ if (errcnt > 0) { dyio_outfmt(ttyout,dy_gtxecho, "\n ERROR: %d total errors for all tests.\n\n", errcnt) ; } else { dyio_outfmt(ttyout,dy_gtxecho, "\n All tests completed successfully.\n\n") ; } dy_freebasis() ; /* Final cleanup. Free space used by the remaining main_* structures and close down any i/o. */ if (main_lp != NULL) { dy_freesoln(main_lp) ; if (main_lp->consys != NULL) consys_free(main_lp->consys) ; FREE(main_lp) ; } if (main_lpopts != NULL) FREE(main_lpopts) ; if (main_lptols != NULL) FREE(main_lptols) ; if (outchn != IOID_INV && outchn != ttyout) { (void) dyio_closefile(outchn) ; } if (dy_logchn != IOID_INV && dy_logchn != IOID_NOSTRM) { (void) dyio_closefile(dy_logchn) ; } dyio_ioterm() ; errterm() ; return (errcnt) ; }
dyret_enum dy_addtopivrej (int j, dyret_enum why, double abarij, double maxabarij) /* This routine adds x<j> to the rejected pivot list by adding an entry to pivrejlst and adding the NOPIVOT qualifier to x<j>'s status. If necessary, it expands the size of the list. Parameter: j: the variable x<j> why: the reason it's going on the pivot reject list; one of dyrSINGULAR or dyrMADPIV abarij: (why == dyrMADPIV) the pivot element maxabarij: (why == dyrMADPIV) the maximum pivot element in the pivot column (primal) or row (dual). Returns: dyrOK if the entry is added without error, dyrFATAL if we can't get more space, or if a paranoid check fails. */ { int n,ndx,newsze ; double ratio ; const char *rtnnme = "dy_addtopivrej" ; # ifndef DYLP_NDEBUG int saveprint ; saveprint = dy_opts->print.pivoting ; dy_opts->print.pivoting = 0 ; # endif /* We don't actually need the pivot ratio until further down, but it's handy to do it here where we can easily suppress the internal print, then restore the print level. */ ratio = dy_chkpiv(abarij,maxabarij) ; n = dy_sys->varcnt ; # ifndef DYLP_NDEBUG dy_opts->print.pivoting = saveprint ; # endif # ifdef DYLP_PARANOIA if (j < 1 || j > n) { errmsg(102,rtnnme,dy_sys->nme,"variable",j,1,n) ; return (dyrFATAL) ; } if (!(why == dyrSINGULAR || why == dyrMADPIV)) { errmsg(1,rtnnme,__LINE__) ; return (dyrFATAL) ; } # endif # ifndef DYLP_NDEBUG /* The default case in this switch is needed to suppress GCC warnings --- it doesn't grok the paranoid check. */ if (dy_opts->print.pivreject >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n marking %s (%d) ineligible for pivoting ", consys_nme(dy_sys,'v',j,TRUE,NULL),j) ; switch (why) { case dyrSINGULAR: { dyio_outfmt(dy_logchn,dy_gtxecho,"(%s).",dy_prtdyret(why)) ; break ; } case dyrMADPIV: { dyio_outfmt(dy_logchn,dy_gtxecho,"(%s = %g).",dy_prtdyret(why),ratio) ; break ; } default: { errmsg(1,rtnnme,__LINE__) ; return (dyrFATAL) ; } } } # endif /* Flag the culprit --- the extent of externally visible activity. Then make the entry in the pivot reject list. Check for adequate list length and expand if necessary. */ setflg(dy_status[j],vstatNOPIVOT) ; ndx = pivrej_ctl.cnt++ ; if (ndx >= pivrej_ctl.sze) { newsze = minn(2*pivrej_ctl.sze,n+1) ; # ifndef DYLP_NDEBUG if (dy_opts->print.pivreject >= 3) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n%s: expanding pivot reject list from %d to %d entries.", rtnnme,pivrej_ctl.sze,newsze) ; } # endif pivrejlst = (pivrej_struct *) REALLOC(pivrejlst,newsze*sizeof(pivrej_struct)) ; if (pivrejlst == NULL) { errmsg(337,rtnnme,dy_sys->nme,pivrej_ctl.sze,newsze) ; return (dyrFATAL) ; } pivrej_ctl.sze = newsze ; } pivrejlst[ndx].ndx = j ; pivrejlst[ndx].iter = dy_lp->basis.pivs ; pivrejlst[ndx].why = why ; switch (why) { case dyrSINGULAR: { pivrej_ctl.sing++ ; break ; } case dyrMADPIV: { pivrej_ctl.mad++ ; ratio = dy_chkpiv(abarij,maxabarij) ; pivrejlst[ndx].ratio = ratio*dy_tols->pivot ; break ; } default: { errmsg(1,rtnnme,__LINE__) ; return (dyrFATAL) ; } } # ifdef DYLP_STATISTICS if (dy_stats != NULL) { switch (why) { case dyrSINGULAR: { dy_stats->pivrej.sing++ ; break ; } case dyrMADPIV: { dy_stats->pivrej.mad++ ; break ; } default: { errmsg(1,rtnnme,__LINE__) ; return (dyrFATAL) ; } } if (pivrej_ctl.cnt > dy_stats->pivrej.max) { dy_stats->pivrej.max = pivrej_ctl.cnt ; } } # endif return (dyrOK) ; }