binary.c

Go to the documentation of this file.
00001 /****************************************************************************/
00002 /*                                                                          */
00003 /*  This file is part of QSopt_ex.                                          */
00004 /*                                                                          */
00005 /*  (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash,      */
00006 /*  and Daniel Espinoza                                                     */
00007 /*                                                                          */
00008 /*  Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his     */
00009 /*  copyright in QSopt.                                                     */
00010 /*                                                                          */
00011 /*  This code may be used under the terms of the GNU General Public License */
00012 /*  (Version 2.1 or later) as published by the Free Software Foundation.    */
00013 /*                                                                          */
00014 /*  Alternatively, use is granted for research purposes only.               */
00015 /*                                                                          */
00016 /*  It is your choice of which of these two licenses you are operating      */
00017 /*  under.                                                                  */
00018 /*                                                                          */
00019 /*  We make no guarantees about the correctness or usefulness of this code. */
00020 /*                                                                          */
00021 /****************************************************************************/
00022 
00023 /* RCS_INFO = "$RCSfile: binary.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */
00024 static int TRACE = 0;
00025 
00026 /****************************************************************************/
00027 /*                                                                          */
00028 /*                     Simple MIP Code to test LP Solver                    */
00029 /*                                                                          */
00030 /*  EXPORTED FUNCTIONS                                                      */
00031 /*                                                                          */
00032 /*    int ILLmip_bfs (lpinfo *lp, double *val, double *x)                   */
00033 /*                                                                          */
00034 /*  NOTES                                                                   */
00035 /*                                                                          */
00036 /*                                                                          */
00037 /****************************************************************************/
00038 
00039 #include "econfig.h"
00040 #include "priority.h"
00041 #include "sortrus.h"
00042 #include "iqsutil.h"
00043 #include "lpdata.h"
00044 #include "lpdefs.h"
00045 #include "simplex.h"
00046 #include "binary.h"
00047 #include "price.h"
00048 #include "lib.h"
00049 #include "qstruct.h"
00050 #include "qsopt.h"
00051 #ifdef USEDMALLOC
00052 #include "dmalloc.h"
00053 #endif
00054 
00055 /*#define  ILL_INTTOL (0.000001)*/
00056 #define ILL_INTTOL PFEAS_TOLER
00057 
00058 #define  STRONG_PIVOTS     (50)
00059 #define  STRONG_CANDIDATES (10)
00060 
00061 #define ILL_BRANCH_STRONG_WEIGHT (10)
00062 #define ILL_BRANCH_STRONG_VAL(v0,v1)                                 \
00063     (((v0) < (v1) ? (ILL_BRANCH_STRONG_WEIGHT * (v0) + (v1))         \
00064                   : (ILL_BRANCH_STRONG_WEIGHT * (v1) + (v0)))        \
00065                     / (ILL_BRANCH_STRONG_WEIGHT + 1.0))
00066 
00067 #define ILL_BRANCH_PENALTY_WEIGHT (2)
00068 #define ILL_BRANCH_PENALTY_VAL(v0,v1,f)                              \
00069     (((v0)*(f) < (v1)*(1.0-(f)) ?                                    \
00070         (ILL_BRANCH_PENALTY_WEIGHT * (v0)*(f) + (v1)*(1.0-(f)))    \
00071       : (ILL_BRANCH_PENALTY_WEIGHT * (v1)*(1.0-(f)) + (v0)*(f)))    \
00072                     / (ILL_BRANCH_PENALTY_WEIGHT + 1.0))
00073 
00074 
00075 
00076 #define FIRSTBRANCH  1
00077 #define MIDDLEBRANCH 2
00078 #define STRONGBRANCH 3
00079 #define PENALTYBRANCH 4
00080 
00081 
00082 typedef struct bbnode
00083 {
00084   struct bbnode *next;
00085   struct bbnode *prev;
00086   int id;
00087   int depth;
00088   int handle;
00089   EGlpNum_t bound;
00090   char *cstat;
00091   char *rstat;
00092   EGlpNum_t *rownorms;
00093   int rownorms_size;
00094   int bound_cnt;
00095   int *bound_indx;
00096   char *lu;
00097   EGlpNum_t *bounds;
00098   int bounds_size;
00099 }
00100 bbnode;
00101 
00102 typedef struct mipinfo
00103 {
00104   int branching_rule;
00105   int watch;
00106   int depth;
00107   int totalnodes;
00108   int activenodes;
00109   int totalpivots;
00110   int lastpivots;
00111   int objsense;
00112   EGlpNum_t objectivebound;
00113   EGlpNum_t value;
00114   EGlpNum_t *downpen;
00115   EGlpNum_t *uppen;
00116   EGlpNum_t *x;
00117   EGlpNum_t *bestx;
00118   EGlpNum_t *orig_lower;
00119   EGlpNum_t *orig_upper;
00120   EGlpNum_t *lower;
00121   EGlpNum_t *upper;
00122   int nstruct;                  /* size of all EGlpNum_t arrays */
00123   lpinfo *lp;
00124   price_info *pinf;
00125   bbnode head_bbnode;
00126   ILLpriority *que;
00127   ILLptrworld ptrworld;
00128 }
00129 mipinfo;
00130 
00131 
00132 ILL_PTRWORLD_ROUTINES (bbnode, bbnodealloc, bbnode_bulkalloc, bbnodefree)
00133 ILL_PTRWORLD_LISTFREE_ROUTINE (bbnode, bbnode_listfree, bbnodefree)
00134 ILL_PTRWORLD_LEAKS_ROUTINE (bbnode, bbnode_check_leaks, depth, int)
00135 static void cleanup_mip ( mipinfo * minf), 
00136     choose_initial_price ( price_info * pinf), 
00137     best_bbnode ( mipinfo * minf, bbnode ** best),
00138     put_bbnode ( mipinfo * minf, bbnode * b),
00139     remove_bbnode ( bbnode * b),
00140     find_first_branch ( lpinfo * lp, EGlpNum_t * x, int *bvar),
00141     find_middle_branch ( lpinfo * lp, EGlpNum_t * x, int *bvar),
00142     check_integral ( lpinfo * lp, EGlpNum_t * x, int *yesno),
00143     copy_x ( int nstruct, EGlpNum_t * from_x, EGlpNum_t * to_x),
00144     init_mipinfo ( mipinfo * minf),
00145     free_mipinfo ( mipinfo * minf),
00146     init_bbnode ( bbnode * b),
00147     free_bbnode ( bbnode * b);
00148 
00149 static int startup_mip ( mipinfo * minf, lpinfo * lp, price_info * pinf,
00150       EGlpNum_t * lpval, itcnt_t*itcnt),
00151     run_bfs ( mipinfo * minf, itcnt_t*itcnt),
00152     process_bfs_bbnode ( mipinfo * minf, bbnode * b, itcnt_t*itcnt),
00153     child_work ( mipinfo * minf, bbnode * active, int bvar, int bdir,
00154       EGlpNum_t * cval, int *cp, itcnt_t*itcnt),
00155     fix_variables ( lpinfo * lp, EGlpNum_t * bestval, bbnode * b,
00156       EGlpNum_t * wupper, EGlpNum_t * wlower, int *hit),
00157     find_branch ( mipinfo * minf, EGlpNum_t * x, EGlpNum_t * lpval,
00158       int *bvar, itcnt_t*itcnt),
00159     find_penalty_branch ( lpinfo * lp, price_info * pinf, EGlpNum_t * x,
00160       EGlpNum_t * downpen, EGlpNum_t * uppen, EGlpNum_t * lpval, int *bvar,
00161       itcnt_t*itcnt),
00162     find_strong_branch ( lpinfo * lp, price_info * pinf, EGlpNum_t * x,
00163       int *bvar, itcnt_t*itcnt),
00164     plunge ( mipinfo * minf, itcnt_t*itcnt),
00165     plunge_work ( mipinfo * minf, int depth, itcnt_t*itcnt),
00166     round_variables ( mipinfo * minf, int *count, EGlpNum_t * tol);
00167 
00168 static void choose_initial_price ( price_info * pinf)
00169 {
00170   pinf->pI_price = QS_PRICE_PSTEEP;
00171   pinf->pII_price = QS_PRICE_PSTEEP;
00172   pinf->dI_price = QS_PRICE_DSTEEP;
00173   pinf->dII_price = QS_PRICE_DSTEEP;
00174 }
00175 
00176 int ILLmip_bfs (
00177   lpinfo * lp,
00178   EGlpNum_t * val,
00179   EGlpNum_t * x,
00180   itcnt_t*itcnt)
00181 {
00182   int tval, rval = 0;
00183   price_info pinf;
00184   mipinfo minf;
00185   bbnode *b;
00186   EGlpNum_t lpval;
00187   double szeit = ILLutil_zeit ();
00188 
00189   EGlpNumInitVar (lpval);
00190   EGlpNumInitVar (pinf.htrigger);
00191 
00192   ILLprice_init_pricing_info (&pinf);
00193   init_mipinfo (&minf);
00194 
00195   if (!lp)
00196   {
00197     fprintf (stderr, "ILLmip_bfs called without an LP\n");
00198     rval = 1;
00199     goto CLEANUP;
00200   }
00201 
00202   rval = startup_mip (&minf, lp, &pinf, &lpval, itcnt);
00203   ILL_CLEANUP_IF (rval);
00204 
00205   ILL_SAFE_MALLOC (minf.que, 1, ILLpriority);
00206   rval = ILLutil_priority_init (minf.que, lp->O->nstruct + 1);
00207   ILL_CLEANUP_IF (rval);
00208 
00209   b = bbnodealloc (&minf.ptrworld);
00210   init_bbnode (b);
00211   b->depth = 0;
00212   b->id = minf.totalnodes++;
00213   EGlpNumCopy (b->bound, lpval);
00214   ILL_SAFE_MALLOC (b->cstat, lp->O->nstruct, char);
00215   ILL_SAFE_MALLOC (b->rstat, lp->nrows, char);
00216 
00217   rval = ILLlib_getbasis (lp, b->cstat, b->rstat);
00218   ILL_CLEANUP_IF (rval);
00219 
00220   if (pinf.dII_price == QS_PRICE_DSTEEP)
00221   {
00222     b->rownorms = EGlpNumAllocArray (lp->nrows);
00223     tval = ILLlib_getrownorms (lp, &pinf, b->rownorms);
00224     if (tval)
00225     {
00226       printf ("Row norms not available\n");
00227       fflush (stdout);
00228       EGlpNumFreeArray (b->rownorms);
00229     }
00230   }
00231 
00232   rval = ILLutil_priority_insert (minf.que, (void *) b, &lpval, &(b->handle));
00233   ILL_CLEANUP_IF (rval);
00234 
00235   b->prev = &(minf.head_bbnode);
00236   b->next = 0;
00237   minf.head_bbnode.next = b;
00238   minf.activenodes++;
00239 
00240   minf.branching_rule = PENALTYBRANCH;
00241 
00242   rval = run_bfs (&minf, itcnt);
00243   ILL_CLEANUP_IF (rval);
00244 
00245   printf ("Total Number of Nodes: %d\n", minf.totalnodes);
00246   printf ("Total Number of Pivots: %d\n", minf.totalpivots);
00247   printf ("BFS MIP Runing Time: %.2f seconds\n", ILLutil_zeit () - szeit);
00248   fflush (stdout);
00249 
00250   EGlpNumCopy (*val, minf.value);
00251   if (minf.objsense == ILL_MAX)
00252     EGlpNumSign (*val);
00253 
00254   if (x && EGlpNumIsNeqq (minf.value, ILL_MAXDOUBLE))
00255   {
00256     copy_x (lp->O->nstruct, minf.bestx, x);
00257   }
00258 
00259 CLEANUP:
00260 
00261   if (minf.que)
00262   {
00263     ILLutil_priority_free (minf.que);
00264     ILL_IFFREE (minf.que, ILLpriority);
00265   }
00266   cleanup_mip (&minf);
00267   free_mipinfo (&minf);
00268   ILLprice_free_pricing_info (&pinf);
00269   EGlpNumClearVar (lpval);
00270   EGlpNumClearVar (pinf.htrigger);
00271   ILL_RETURN (rval, "ILLmip_bfs");
00272 }
00273 
00274 static int startup_mip (
00275   mipinfo * minf,
00276   lpinfo * lp,
00277   price_info * pinf,
00278   EGlpNum_t * lpval,
00279   itcnt_t*itcnt)
00280 {
00281   int rval = 0;
00282   int i, col, status, intcount = 0;
00283   EGlpNum_t val;
00284   ILLlpdata *qlp;
00285 
00286   EGlpNumInitVar (val);
00287 
00288   choose_initial_price (pinf);
00289 
00290   qlp = lp->O;
00291 
00292   rval = ILLlib_optimize (lp, 0, pinf, DUAL_SIMPLEX, &status, 0, itcnt);
00293   ILL_CLEANUP_IF (rval);
00294 
00295   minf->totalpivots += ILLlib_iter (lp);
00296 
00297   rval = ILLlib_objval (lp, 0, &val);
00298   ILL_CLEANUP_IF (rval);
00299 
00300   printf ("LP Value: %.6f\n", EGlpNumToLf (val));
00301   fflush (stdout);
00302   if (lpval)
00303     EGlpNumCopy (*lpval, val);
00304 
00305   if (qlp->intmarker)
00306   {
00307     for (i = 0; i < qlp->nstruct; i++)
00308     {
00309       if (qlp->intmarker[i])
00310       {
00311         col = qlp->structmap[i];
00312         intcount++;
00313         if (EGlpNumIsEqqual (qlp->lower[col], ILL_MINDOUBLE)
00314             || EGlpNumIsEqqual (qlp->upper[col], ILL_MAXDOUBLE))
00315         {
00316           printf ("Instance has unbounded integer variable\n");
00317           fflush (stdout);
00318           rval = 1;
00319           goto CLEANUP;
00320         }
00321       }
00322     }
00323   }
00324 
00325   if (intcount == 0)
00326   {
00327     printf ("No integer variables\n");
00328     fflush (stdout);
00329     rval = 1;
00330     goto CLEANUP;
00331   }
00332   else
00333   {
00334     printf ("%d integer variables\n", intcount);
00335     fflush (stdout);
00336   }
00337 
00338   if (qlp->sinfo)
00339   {                             /* Free the presolve LP and work with orginal */
00340     ILLlp_sinfo_free (qlp->sinfo);
00341     ILL_IFFREE (qlp->sinfo, ILLlp_sinfo);
00342   }
00343 
00344 
00345   minf->lp = lp;
00346   minf->pinf = pinf;
00347   minf->objsense = qlp->objsense;
00348   if (qlp->objsense == ILL_MAX)
00349   {                             /* MIP codes work with min */
00350     for (i = 0; i < lp->ncols; i++)
00351     {
00352       EGlpNumCopyNeg (qlp->obj[i], qlp->obj[i]);
00353     }
00354     qlp->objsense = ILL_MIN;
00355   }
00356 
00357   minf->x = EGlpNumAllocArray (qlp->nstruct);
00358   minf->bestx = EGlpNumAllocArray (qlp->nstruct);
00359   minf->lower = EGlpNumAllocArray (qlp->nstruct);
00360   minf->upper = EGlpNumAllocArray (qlp->nstruct);
00361   minf->orig_lower = EGlpNumAllocArray (qlp->nstruct);
00362   minf->orig_upper = EGlpNumAllocArray (qlp->nstruct);
00363   minf->downpen = EGlpNumAllocArray (qlp->nstruct);
00364   minf->uppen = EGlpNumAllocArray (qlp->nstruct);
00365   minf->nstruct = qlp->nstruct;
00366 
00367   rval = ILLlib_get_x (lp, 0, minf->x);
00368   ILL_CLEANUP_IF (rval);
00369 
00370   for (i = 0; i < qlp->nstruct; i++)
00371   {
00372     EGlpNumCopy (minf->lower[i], qlp->lower[i]);
00373     EGlpNumCopy (minf->upper[i], qlp->upper[i]);
00374     EGlpNumCopy (minf->orig_lower[i], qlp->lower[i]);
00375     EGlpNumCopy (minf->orig_upper[i], qlp->upper[i]);
00376     EGlpNumOne (minf->downpen[i]);
00377     EGlpNumOne (minf->uppen[i]);
00378     EGlpNumSign (minf->downpen[i]);
00379     EGlpNumSign (minf->uppen[i]);
00380   }
00381 
00382 
00383 CLEANUP:
00384 
00385   EGlpNumClearVar (val);
00386   ILL_RETURN (rval, "startup_mip");
00387 }
00388 
00389 static void cleanup_mip (
00390   mipinfo * minf)
00391 {
00392   int i;
00393   ILLlpdata *qslp;
00394 
00395   if (minf && minf->lp)
00396   {
00397     qslp = minf->lp->O;
00398     if (minf->objsense == ILL_MAX)
00399     {
00400       for (i = 0; i < minf->lp->ncols; i++)
00401       {
00402         EGlpNumSign (qslp->obj[i]);
00403       }
00404       qslp->objsense = ILL_MIN;
00405     }
00406   }
00407 }
00408 
00409 static int run_bfs (
00410   mipinfo * minf,
00411   itcnt_t*itcnt)
00412 {
00413   int rval = 0;
00414   bbnode *b;
00415 
00416   while (minf->head_bbnode.next)
00417   {
00418     best_bbnode (minf, &b);
00419     rval = process_bfs_bbnode (minf, b, itcnt);
00420     ILL_CLEANUP_IF (rval);
00421     remove_bbnode (b);
00422     free_bbnode (b);
00423     bbnodefree (&minf->ptrworld, b);
00424     minf->activenodes--;
00425   }
00426 
00427 CLEANUP:
00428 
00429   ILL_RETURN (rval, "run_bfs");
00430 }
00431 
00432 static int process_bfs_bbnode (
00433   mipinfo * minf,
00434   bbnode * active,
00435   itcnt_t*itcnt)
00436 {
00437   lpinfo *lp = minf->lp;
00438   ILLlp_basis B;
00439   int status, bvar = 0;
00440   int i, j, hit, dnp = 0, upp = 0;
00441   int nstruct = lp->O->nstruct;
00442   EGlpNum_t t, lpval, dnval, upval;
00443   EGlpNum_t *wupper = 0;
00444   EGlpNum_t *wlower = 0;
00445   int rval = 0;
00446 
00447   EGlpNumInitVar (t);
00448   EGlpNumInitVar (lpval);
00449   EGlpNumInitVar (dnval);
00450   EGlpNumInitVar (upval);
00451 
00452   ILLlp_basis_init (&B);
00453 
00454   if (minf->watch > 1)
00455   {
00456     printf ("Node %4d: %.3f", active->id, EGlpNumToLf (active->bound));
00457     if (EGlpNumIsNeqq (minf->value, ILL_MAXDOUBLE))
00458       printf (" %.3f", EGlpNumToLf (minf->value));
00459     else
00460       printf ("  None");
00461     printf (", Active %d ", minf->activenodes);
00462     fflush (stdout);
00463   }
00464   else if (minf->watch == 1)
00465   {
00466     if (minf->lastpivots > 1000)
00467     {
00468       minf->lastpivots = 0;
00469       printf ("Pivots %d, Active Nodes %d, Bound %.3f, Soln ",
00470               minf->totalpivots, minf->activenodes,
00471               EGlpNumToLf (active->bound));
00472       if (!EGlpNumIsLess (minf->value, ILL_MAXDOUBLE))
00473         printf ("%.3f", EGlpNumToLf (minf->value));
00474       else
00475         printf ("None\n");
00476     }
00477   }
00478 
00479   if (EGlpNumIsLeq (minf->objectivebound, active->bound))
00480   {
00481     if (minf->watch > 1)
00482     {
00483       printf ("  Node can be purged\n");
00484       fflush (stdout);
00485     }
00486     goto CLEANUP;
00487   }
00488 
00489   /*  Set the LP bounds for the node. */
00490 
00491   wlower = EGlpNumAllocArray (nstruct);
00492   wupper = EGlpNumAllocArray (nstruct);
00493 
00494   for (i = 0; i < nstruct; i++)
00495   {
00496     EGlpNumCopy (wlower[i], minf->orig_lower[i]);
00497     EGlpNumCopy (wupper[i], minf->orig_upper[i]);
00498   }
00499   for (i = 0; i < active->bound_cnt; i++)
00500   {
00501     j = active->bound_indx[i];
00502     if (active->lu[i] == 'L')
00503       EGlpNumCopy (wlower[j], active->bounds[i]);
00504     else
00505       EGlpNumCopy (wupper[j], active->bounds[i]);
00506   }
00507 
00508   if (active->bound_cnt > 0)
00509   {
00510     rval = ILLlib_chgbnds (lp, active->bound_cnt, active->bound_indx,
00511                            active->lu, active->bounds);
00512     ILL_CLEANUP_IF (rval);
00513   }
00514 
00515   /*  Solve the LP. */
00516 
00517   rval = ILLlib_loadbasis (&B, nstruct, lp->nrows, active->cstat,
00518                            active->rstat);
00519   ILL_CLEANUP_IF (rval);
00520   if (active->rownorms)
00521   {
00522     B.rownorms = EGlpNumAllocArray (lp->nrows);
00523     for (i = 0; i < lp->nrows; i++)
00524     {
00525       EGlpNumCopy (B.rownorms[i], active->rownorms[i]);
00526     }
00527   }
00528 
00529   rval = ILLlib_optimize (lp, &B, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
00530   ILL_CLEANUP_IF (rval);
00531 
00532   minf->totalpivots += ILLlib_iter (lp);
00533   minf->lastpivots += ILLlib_iter (lp);
00534 
00535   if (status == QS_LP_UNSOLVED)
00536   {
00537     printf ("Simplex did not solve the LP\n");
00538     fflush (stdout);
00539     rval = 1;
00540     ILL_CLEANUP;
00541   }
00542 
00543   if (status == QS_LP_INFEASIBLE)
00544   {
00545     printf ("  Infeasible LP, should have been purged earlier\n");
00546     fflush (stdout);
00547     rval = 1;
00548     ILL_CLEANUP;
00549   }
00550 
00551   if (active->depth < 0)
00552   {
00553     for (i = 0; i < nstruct; i++)
00554     {
00555       EGlpNumCopy (minf->lower[i], wlower[i]);
00556       EGlpNumCopy (minf->upper[i], wupper[i]);
00557     }
00558     rval = plunge (minf, itcnt);
00559     ILL_CLEANUP_IF (rval);
00560   }
00561 
00562   /*  Fix variables. */
00563 
00564   if (EGlpNumIsLess (minf->value, ILL_MAXDOUBLE))
00565   {
00566     rval = fix_variables (lp, &(minf->value), active, wupper, wlower, &hit);
00567     ILL_CLEANUP_IF (rval);
00568 
00569     if (hit)
00570     {
00571       rval = ILLlib_optimize (lp, &B, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
00572       ILL_CLEANUP_IF (rval);
00573 
00574       minf->totalpivots += ILLlib_iter (lp);
00575       minf->lastpivots += ILLlib_iter (lp);
00576 
00577       if (status == QS_LP_UNSOLVED)
00578       {
00579         printf ("Simplex did not solve the LP\n");
00580         fflush (stdout);
00581         rval = 1;
00582         ILL_CLEANUP;
00583       }
00584 
00585       if (status == QS_LP_INFEASIBLE)
00586       {
00587         printf ("  Infeasible LP after fixing\n");
00588         fflush (stdout);
00589         rval = 1;
00590         ILL_CLEANUP;
00591       }
00592     }
00593   }
00594 
00595 
00596   /*  Branch. */
00597 
00598   rval = ILLlib_get_x (lp, 0, minf->x);
00599   ILL_CLEANUP_IF (rval);
00600 
00601   rval = ILLlib_objval (lp, 0, &lpval);
00602   ILL_CLEANUP_IF (rval);
00603 
00604   rval = find_branch (minf, minf->x, &lpval, &bvar, itcnt);
00605   ILL_CLEANUP_IF (rval);
00606 
00607   if (bvar == -1)
00608   {
00609     printf ("Found integral solution: %f\n", EGlpNumToLf (lpval));
00610     if (EGlpNumIsLess (lpval, minf->value))
00611     {
00612       EGlpNumCopy (minf->value, lpval);
00613       EGlpNumCopy (minf->objectivebound, lpval);
00614       EGlpNumSubTo (minf->objectivebound, ILL_INTTOL);
00615       copy_x (nstruct, minf->x, minf->bestx);
00616     }
00617   }
00618   else
00619   {
00620     /* Create down child */
00621 
00622     rval = child_work (minf, active, bvar, 'D', &dnval, &dnp, itcnt);
00623     ILL_CLEANUP_IF (rval);
00624 
00625     /* Restore parent basis */
00626 
00627     rval = ILLlib_loadbasis (&B, nstruct, lp->nrows, active->cstat,
00628                              active->rstat);
00629     ILL_CLEANUP_IF (rval);
00630     if (active->rownorms)
00631     {
00632       B.rownorms = EGlpNumAllocArray (lp->nrows);
00633       for (i = 0; i < lp->nrows; i++)
00634       {
00635         EGlpNumCopy (B.rownorms[i], active->rownorms[i]);
00636       }
00637     }
00638 
00639     /* Create up child */
00640 
00641     rval = child_work (minf, active, bvar, 'U', &upval, &upp, itcnt);
00642     ILL_CLEANUP_IF (rval);
00643 
00644     if (minf->watch > 1)
00645     {
00646       if (EGlpNumIsEqqual (dnval, ILL_MAXDOUBLE))
00647       {
00648         printf ("DN->XXX");
00649       }
00650       else
00651       {
00652         printf ("DN->%.3f%c", EGlpNumToLf (dnval), dnp ? 'X' : ' ');
00653       }
00654       if (EGlpNumIsEqqual (upval, ILL_MAXDOUBLE))
00655       {
00656         printf ("UP->XXX\n");
00657       }
00658       else
00659       {
00660         printf ("UP->%.3f%c\n", EGlpNumToLf (upval), upp ? 'X' : ' ');
00661       }
00662       fflush (stdout);
00663     }
00664   }
00665 
00666   /* Set the LP bounds back to original values */
00667 
00668   for (i = 0; i < active->bound_cnt; i++)
00669   {
00670     if (active->lu[i] == 'L')
00671       EGlpNumCopy (t, minf->orig_lower[active->bound_indx[i]]);
00672     else
00673       EGlpNumCopy (t, minf->orig_upper[active->bound_indx[i]]);
00674 
00675     rval = ILLlib_chgbnd (lp, active->bound_indx[i], active->lu[i], t);
00676     ILL_CLEANUP_IF (rval);
00677   }
00678 
00679 CLEANUP:
00680 
00681   EGlpNumFreeArray (wlower);
00682   EGlpNumFreeArray (wupper);
00683   ILLlp_basis_free (&B);
00684   EGlpNumClearVar (t);
00685   EGlpNumClearVar (lpval);
00686   EGlpNumClearVar (dnval);
00687   EGlpNumClearVar (upval);
00688   ILL_RETURN (rval, "process_bfs_bbnode");
00689 }
00690 
00691 static int child_work (
00692   mipinfo * minf,
00693   bbnode * active,
00694   int bvar,
00695   int bdir,
00696   EGlpNum_t * cval,
00697   int *cp,
00698   itcnt_t*itcnt)
00699 {
00700   int tval, rval = 0;
00701   int i, status, intsol;
00702   EGlpNum_t t, oldt, lpval;
00703   EGlpNum_t *xi = &(minf->x[bvar]);
00704   lpinfo *lp = minf->lp;
00705   bbnode *b;
00706 
00707   EGlpNumInitVar (t);
00708   EGlpNumInitVar (lpval);
00709   EGlpNumInitVar (oldt);
00710 
00711   *cp = 0;
00712 
00713   if (bdir == 'D')
00714   {
00715     rval = ILLlib_getbnd (lp, bvar, 'U', &oldt);
00716     ILL_CLEANUP_IF (rval);
00717     EGlpNumFloor (t, *xi);
00718     rval = ILLlib_chgbnd (lp, bvar, 'U', t);
00719     ILL_CLEANUP_IF (rval);
00720   }
00721   else
00722   {
00723     rval = ILLlib_getbnd (lp, bvar, 'L', &oldt);
00724     ILL_CLEANUP_IF (rval);
00725     EGlpNumCeil (t, *xi);
00726     rval = ILLlib_chgbnd (lp, bvar, 'L', t);
00727     ILL_CLEANUP_IF (rval);
00728   }
00729 
00730   rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
00731   ILL_CLEANUP_IF (rval);
00732 
00733   minf->totalpivots += ILLlib_iter (lp);
00734   minf->lastpivots += ILLlib_iter (lp);
00735 
00736   if (status == QS_LP_UNSOLVED)
00737   {
00738     printf ("Simplex did not solve Child LP\n");
00739     fflush (stdout);
00740     rval = 1;
00741     ILL_CLEANUP;
00742   }
00743 
00744   if (status == QS_LP_INFEASIBLE)
00745   {
00746     EGlpNumCopy (*cval, ILL_MAXDOUBLE);
00747     *cp = 1;
00748   }
00749   else
00750   {
00751     rval = ILLlib_objval (lp, 0, &lpval);
00752     ILL_CLEANUP_IF (rval);
00753     EGlpNumCopy (*cval, lpval);
00754 
00755     /* What about the x vector?  Bico - 020531 */
00756 
00757     check_integral (lp, minf->x, &intsol);
00758     if (intsol)
00759     {
00760       if (EGlpNumIsLess (lpval, minf->value))
00761       {
00762         printf ("Found integral solution: %f\n", EGlpNumToLf (lpval));
00763         EGlpNumCopy (minf->value, lpval);
00764         EGlpNumCopy (minf->objectivebound, lpval);
00765         EGlpNumSubTo (minf->objectivebound, ILL_INTTOL);
00766         copy_x (lp->O->nstruct, minf->x, minf->bestx);
00767       }
00768     }
00769 
00770     if (EGlpNumIsLeq (minf->objectivebound, lpval))
00771     {
00772       *cp = 1;
00773     }
00774     else
00775     {
00776       b = bbnodealloc (&minf->ptrworld);
00777       init_bbnode (b);
00778       b->depth = active->depth + 1;
00779       b->id = minf->totalnodes;
00780       EGlpNumCopy (b->bound, lpval);
00781       ILL_SAFE_MALLOC (b->cstat, lp->O->nstruct, char);
00782       ILL_SAFE_MALLOC (b->rstat, lp->nrows, char);
00783 
00784       rval = ILLlib_getbasis (lp, b->cstat, b->rstat);
00785       ILL_CLEANUP_IF (rval);
00786       if (minf->pinf->dII_price == QS_PRICE_DSTEEP)
00787       {
00788         b->rownorms = EGlpNumAllocArray (lp->nrows);
00789         tval = ILLlib_getrownorms (lp, minf->pinf, b->rownorms);
00790         if (tval)
00791         {
00792           printf ("Row norms not available\n");
00793           fflush (stdout);
00794           printf ("A\n");
00795           exit (1);
00796           EGlpNumFreeArray (b->rownorms);
00797         }
00798       }
00799       ILL_SAFE_MALLOC (b->bound_indx, active->bound_cnt + 1, int);
00800       ILL_SAFE_MALLOC (b->lu, active->bound_cnt + 1, char);
00801 
00802       b->bounds = EGlpNumAllocArray (active->bound_cnt + 1);
00803       for (i = 0; i < active->bound_cnt; i++)
00804       {
00805         b->bound_indx[i] = active->bound_indx[i];
00806         b->lu[i] = active->lu[i];
00807         EGlpNumCopy (b->bounds[i], active->bounds[i]);
00808       }
00809       b->bound_indx[active->bound_cnt] = bvar;
00810       if (bdir == 'D')
00811         b->lu[active->bound_cnt] = 'U';
00812       else
00813         b->lu[active->bound_cnt] = 'L';
00814       EGlpNumCopy (b->bounds[active->bound_cnt], t);
00815       b->bound_cnt = active->bound_cnt + 1;
00816 
00817       rval = ILLutil_priority_insert (minf->que, (void *) b, &lpval,
00818                                       &(b->handle));
00819       ILL_CLEANUP_IF (rval);
00820 
00821       put_bbnode (minf, b);
00822       minf->activenodes++;
00823     }
00824   }
00825   minf->totalnodes++;
00826 
00827   if (bdir == 'D')
00828   {
00829     rval = ILLlib_chgbnd (lp, bvar, 'U', oldt);
00830     ILL_CLEANUP_IF (rval);
00831   }
00832   else
00833   {
00834     rval = ILLlib_chgbnd (lp, bvar, 'L', oldt);
00835     ILL_CLEANUP_IF (rval);
00836   }
00837 
00838 CLEANUP:
00839 
00840   EGlpNumClearVar (t);
00841   EGlpNumClearVar (lpval);
00842   EGlpNumClearVar (oldt);
00843   return rval;
00844 }
00845 
00846 static int fix_variables (
00847   lpinfo * lp,
00848   EGlpNum_t * bestval,
00849   bbnode * b,
00850   EGlpNum_t * wupper,
00851   EGlpNum_t * wlower,
00852   int *hit)
00853 {
00854   int rval = 0;
00855   int i, nnew = 0;
00856   int nstruct = lp->O->nstruct;
00857   EGlpNum_t delta, lpval;
00858   int *new_indx = 0;
00859   char *new_lu = 0;
00860   EGlpNum_t *new_bounds = 0;
00861   EGlpNum_t *dj = 0;
00862 
00863   EGlpNumInitVar (delta);
00864   EGlpNumInitVar (lpval);
00865 
00866   *hit = 0;
00867 
00868   if (EGlpNumIsLess (*bestval, ILL_MAXDOUBLE))
00869   {
00870     rval = ILLlib_objval (lp, 0, &lpval);
00871     ILL_CLEANUP_IF (rval);
00872     //delta = bestval - lpval + ILL_INTTOL;
00873     EGlpNumCopy (delta, *bestval);
00874     EGlpNumSubTo (delta, lpval);
00875     EGlpNumAddTo (delta, ILL_INTTOL);
00876 
00877     ILL_SAFE_MALLOC (new_indx, nstruct, int);
00878     ILL_SAFE_MALLOC (new_lu, nstruct, char);
00879 
00880     dj = EGlpNumAllocArray (nstruct);
00881     new_bounds = EGlpNumAllocArray (nstruct);
00882 
00883     rval = ILLlib_solution (lp, 0, 0, 0, 0, 0, dj);
00884     ILL_CLEANUP_IF (rval);
00885 
00886     for (i = 0; i < nstruct; i++)
00887     {
00888       if (lp->O->intmarker[i])
00889       {
00890         if (EGlpNumIsNeqq (wlower[i], wupper[i]))
00891         {
00892           if (EGlpNumIsLess (delta, dj[i]))
00893           {
00894             EGlpNumSubTo (wupper[i], oneLpNum);
00895             rval = ILLlib_chgbnd (lp, i, 'U', wupper[i]);
00896             ILL_CLEANUP_IF (rval);
00897             new_indx[nnew] = i;
00898             new_lu[nnew] = 'U';
00899             EGlpNumCopy (new_bounds[nnew], wupper[i]);
00900             nnew++;
00901           }
00902           /*if (-dj[i] > delta) */
00903           EGlpNumSign (delta);
00904           if (EGlpNumIsLess (delta, dj[i]))
00905           {
00906             EGlpNumAddTo (wlower[i], oneLpNum);
00907             rval = ILLlib_chgbnd (lp, i, 'L', wlower[i]);
00908             ILL_CLEANUP_IF (rval);
00909             new_indx[nnew] = i;
00910             new_lu[nnew] = 'L';
00911             EGlpNumCopy (new_bounds[nnew], wlower[i]);
00912             nnew++;
00913           }
00914           EGlpNumSign (delta);
00915         }
00916       }
00917     }
00918 
00919     if (nnew)
00920     {
00921       b->bound_indx =
00922         EGrealloc (b->bound_indx, sizeof (int) * (b->bound_cnt + nnew));
00923       //rval = ILLutil_reallocrus_count ((void **) &(b->bound_indx),
00924       //                                 b->bound_cnt + nnew, sizeof (int));
00925       //ILL_CLEANUP_IF (rval);
00926       b->lu = EGrealloc (b->lu, sizeof (char) * (b->bound_cnt + nnew));
00927       //rval = ILLutil_reallocrus_count ((void **) &(b->lu),
00928       //                                 b->bound_cnt + nnew, sizeof (char));
00929       //ILL_CLEANUP_IF (rval);
00930       EGlpNumReallocArray (&(b->bounds), b->bound_cnt + nnew);
00931       for (i = 0; i < nnew; i++)
00932       {
00933         b->bound_indx[b->bound_cnt + i] = new_indx[i];
00934         b->lu[b->bound_cnt + i] = new_lu[i];
00935         EGlpNumCopy (b->bounds[b->bound_cnt + i], new_bounds[i]);
00936       }
00937       b->bound_cnt += nnew;
00938     }
00939   }
00940 
00941   *hit = nnew;
00942 
00943 CLEANUP:
00944 
00945   ILL_IFFREE (new_indx, int);
00946   ILL_IFFREE (new_lu, char);
00947 
00948   EGlpNumFreeArray (dj);
00949   EGlpNumFreeArray (new_bounds);
00950   EGlpNumClearVar (delta);
00951   EGlpNumClearVar (lpval);
00952   return rval;
00953 }
00954 
00955 static void best_bbnode (
00956   mipinfo * minf,
00957   bbnode ** best)
00958 {
00959 #if 0
00960   bbnode *b;
00961   double bestval = ILL_MAXDOUBLE;
00962 
00963   for (b = minf->head_bbnode.next; b; b = b->next)
00964   {
00965     if (b->bound < bestval)
00966     {
00967       *best = b;
00968       bestval = b->bound;
00969     }
00970   }
00971 #endif
00972 
00973   EGlpNum_t val;
00974 
00975   EGlpNumInitVar (val);
00976   ILLutil_priority_deletemin (minf->que, &val, (void **) best);
00977   EGlpNumClearVar (val);
00978 }
00979 
00980 static void put_bbnode (
00981   mipinfo * minf,
00982   bbnode * b)
00983 {
00984   b->next = minf->head_bbnode.next;
00985   b->prev = &(minf->head_bbnode);
00986   if (b->next)
00987     b->next->prev = b;
00988   minf->head_bbnode.next = b;
00989 }
00990 
00991 static void remove_bbnode (
00992   bbnode * b)
00993 {
00994   b->prev->next = b->next;
00995   if (b->next)
00996     b->next->prev = b->prev;
00997 }
00998 
00999 static int find_branch (
01000   mipinfo * minf,
01001   EGlpNum_t * x,
01002   EGlpNum_t * lpval,
01003   int *bvar,
01004   itcnt_t*itcnt)
01005 {
01006   lpinfo *lp = minf->lp;
01007   int rval = 0;
01008 
01009   switch (minf->branching_rule)
01010   {
01011   case PENALTYBRANCH:
01012     rval = find_penalty_branch (lp, minf->pinf, x, minf->downpen,
01013                                 minf->uppen, lpval, bvar, itcnt);
01014     ILL_CLEANUP_IF (rval);
01015     break;
01016   case FIRSTBRANCH:
01017     find_first_branch (lp, x, bvar);
01018     break;
01019   case MIDDLEBRANCH:
01020     find_middle_branch (lp, x, bvar);
01021     break;
01022   case STRONGBRANCH:
01023     rval = find_strong_branch (lp, minf->pinf, x, bvar, itcnt);
01024     ILL_CLEANUP_IF (rval);
01025     break;
01026   default:
01027     fprintf (stderr, "Unknown branching rule.\n");
01028     rval = 1;
01029     goto CLEANUP;
01030   }
01031 
01032 CLEANUP:
01033 
01034   ILL_RETURN (rval, "find_branch");
01035 }
01036 
01037 static void find_first_branch (
01038   lpinfo * lp,
01039   EGlpNum_t * x,
01040   int *bvar)
01041 {
01042   int i, ibest = -1;
01043   ILLlpdata *qslp = lp->O;
01044   EGlpNum_t t;
01045 
01046   EGlpNumInitVar (t);
01047 
01048   for (i = 0; i < qslp->nstruct; i++)
01049   {
01050     if (qslp->intmarker[i])
01051     {
01052       /*t = ILLutil_our_frac (x[i]); */
01053       EGlpNumFloor (t, x[i]);
01054       EGlpNumSubTo (t, x[i]);
01055       EGlpNumSign (t);
01056       if ((EGlpNumIsNeqZero (t, ILL_INTTOL)) &&
01057           (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL)))
01058       {
01059         ibest = i;
01060         break;
01061       }
01062     }
01063   }
01064   *bvar = ibest;
01065   EGlpNumClearVar (t);
01066 }
01067 
01068 static void find_middle_branch (
01069   lpinfo * lp,
01070   EGlpNum_t * x,
01071   int *bvar)
01072 {
01073   int i, ibest = -1;
01074   EGlpNum_t t, tbest;
01075   ILLlpdata *qlp = lp->O;
01076 
01077   EGlpNumInitVar (t);
01078   EGlpNumInitVar (tbest);
01079   EGlpNumSet (tbest, 0.5);
01080 
01081   for (i = 0; i < qlp->nstruct; i++)
01082   {
01083     if (qlp->intmarker[i])
01084     {
01085       /*t = ILLutil_our_frac (x[i]) - 0.5;
01086        * if (t < 0.0)
01087        * t = -t; */
01088       EGlpNumFloor (t, x[i]);
01089       EGlpNumMultUiTo (t, 2);
01090       EGlpNumSubTo (t, oneLpNum);
01091       EGlpNumDivUiTo (t, 2);
01092       if (EGlpNumIsLessZero (t))
01093         EGlpNumSign (t);
01094       /*if (t < tbest) */
01095       if (EGlpNumIsLess (t, tbest))
01096       {
01097         EGlpNumCopy (tbest, t);
01098         ibest = i;
01099       }
01100     }
01101   }
01102 
01103   /*if (tbest < (0.5 - ILL_INTTOL)) */
01104   EGlpNumAddTo (tbest, ILL_INTTOL);
01105   if (EGlpNumIsLessDbl (tbest, 0.5))
01106   {
01107     *bvar = ibest;
01108   }
01109   else
01110   {
01111     *bvar = -1;
01112   }
01113   EGlpNumClearVar (t);
01114   EGlpNumClearVar (tbest);
01115 }
01116 
01117 static int find_penalty_branch (
01118   lpinfo * lp,
01119   price_info * pinf,
01120   EGlpNum_t * x,
01121   EGlpNum_t * downpen,
01122   EGlpNum_t * uppen,
01123   EGlpNum_t * lpval,
01124   int *bvar,
01125   itcnt_t*itcnt)
01126 {
01127   int rval = 0;
01128   int i, k, ibest = -1, ncand = 0, nneed = 0;
01129   ILLlpdata *qslp = lp->O;
01130   int *candidatelist = 0;
01131   int *needlist = 0;
01132   EGlpNum_t *fval = 0;
01133   EGlpNum_t *xlist = 0;
01134   EGlpNum_t *newdown = 0;
01135   EGlpNum_t *newup = 0;
01136   EGlpNum_t a, t, tbest;
01137 
01138   EGlpNumInitVar (a);
01139   EGlpNumInitVar (t);
01140   EGlpNumInitVar (tbest);
01141   EGlpNumCopy (tbest, ILL_MINDOUBLE);
01142 
01143   ILL_SAFE_MALLOC (candidatelist, qslp->nstruct, int);
01144   ILL_SAFE_MALLOC (needlist, qslp->nstruct, int);
01145 
01146   fval = EGlpNumAllocArray (qslp->nstruct);
01147   xlist = EGlpNumAllocArray (qslp->nstruct);
01148   for (i = 0; i < qslp->nstruct; i++)
01149   {
01150     if (qslp->intmarker[i])
01151     {
01152       /*fval[i] = x[i] - floor(x[i]); */
01153       EGlpNumFloor (fval[i], x[i]);
01154       EGlpNumSubTo (fval[i], x[i]);
01155       EGlpNumSign (fval[i]);
01156       if ((EGlpNumIsNeqZero (fval[i], ILL_INTTOL)) &&
01157           (EGlpNumIsNeq (fval[i], oneLpNum, ILL_INTTOL)))
01158       {
01159         candidatelist[ncand++] = i;
01160         /*if (downpen[i] == -1.0) */
01161         EGlpNumSign (downpen[i]);
01162         if (EGlpNumIsEqqual (downpen[i], oneLpNum))
01163         {
01164           EGlpNumCopy (xlist[nneed], x[i]);
01165           needlist[nneed++] = i;
01166         }
01167         EGlpNumSign (downpen[i]);
01168       }
01169     }
01170   }
01171 
01172   if (nneed > 0)
01173   {
01174     newdown = EGlpNumAllocArray (nneed);
01175     newup = EGlpNumAllocArray (nneed);
01176     rval = ILLlib_strongbranch (lp, pinf, needlist, nneed,
01177                                 0, newdown, newup,
01178                                 5 * STRONG_PIVOTS, ILL_MAXDOUBLE, itcnt);
01179     ILL_CLEANUP_IF (rval);
01180 
01181     for (i = 0; i < nneed; i++)
01182     {
01183       k = needlist[i];
01184       /*uppen[k] = (newup[i] - lpval) / (1.0 - fval[k]); */
01185       EGlpNumCopyDiff (uppen[k], newup[i], *lpval);
01186       EGlpNumCopyDiff (downpen[k], oneLpNum, fval[k]);
01187       EGlpNumDivTo (uppen[k], downpen[k]);
01188       /*downpen[k] = (newdown[i] - lpval) / fval[k]; */
01189       EGlpNumCopyDiffRatio (downpen[k], newdown[i], *lpval, fval[k]);
01190 
01191     }
01192   }
01193 
01194   for (i = 0; i < ncand; i++)
01195   {
01196     k = candidatelist[i];
01197     /*t = ILL_BRANCH_PENALTY_VAL (downpen[k], uppen[k], fval[k]); */
01198     EGlpNumCopy (t, downpen[k]);
01199     EGlpNumMultTo (t, fval[k]);
01200     EGlpNumCopyDiff (a, oneLpNum, fval[k]);
01201     EGlpNumMultTo (a, uppen[k]);
01202     if (EGlpNumIsLess (t, a))
01203     {
01204       EGlpNumMultUiTo (t, ILL_BRANCH_PENALTY_WEIGHT);
01205       EGlpNumAddTo (t, a);
01206     }
01207     else
01208     {
01209       EGlpNumMultUiTo (a, ILL_BRANCH_PENALTY_WEIGHT);
01210       EGlpNumAddTo (t, a);
01211     }
01212     EGlpNumDivUiTo (t, ILL_BRANCH_PENALTY_WEIGHT + 1);
01213 
01214     if (EGlpNumIsLess (tbest, t))
01215     {
01216       EGlpNumCopy (tbest, t);
01217       ibest = k;
01218     }
01219   }
01220 
01221   *bvar = ibest;
01222 
01223 CLEANUP:
01224 
01225   EGlpNumClearVar (a);
01226   EGlpNumClearVar (t);
01227   EGlpNumClearVar (tbest);
01228   EGlpNumFreeArray (newdown);
01229   EGlpNumFreeArray (newup);
01230   EGlpNumFreeArray (fval);
01231   EGlpNumFreeArray (xlist);
01232   ILL_IFFREE (candidatelist, int);
01233   ILL_IFFREE (needlist, int);
01234 
01235   return rval;
01236 }
01237 
01238 static int find_strong_branch (
01239   lpinfo * lp,
01240   price_info * pinf,
01241   EGlpNum_t * x,
01242   int *bvar,
01243   itcnt_t*itcnt)
01244 {
01245   int rval = 0;
01246   int i, ibest = -1, ncand = 0;
01247   int maxtrys = STRONG_CANDIDATES;
01248   EGlpNum_t t, tbest;
01249   ILLlpdata *qlp = lp->O;
01250   int *candidatelist = 0;
01251   int *newlist = 0;
01252   int *perm = 0;
01253   EGlpNum_t *tval = 0;
01254   EGlpNum_t *xlist = 0;
01255   EGlpNum_t *downpen = 0;
01256   EGlpNum_t *uppen = 0;
01257   ILLrandstate rstate;
01258 
01259   EGlpNumInitVar (t);
01260   EGlpNumInitVar (tbest);
01261   EGlpNumCopy (tbest, ILL_MINDOUBLE);
01262 
01263   ILLutil_sprand (999, &rstate);
01264   ILL_SAFE_MALLOC (candidatelist, qlp->nstruct, int);
01265 
01266   tval = EGlpNumAllocArray (qlp->nstruct);
01267 
01268   for (i = 0; i < qlp->nstruct; i++)
01269   {
01270     if (qlp->intmarker[i])
01271     {
01272       /*t = ILLutil_our_frac (x[i]) - 0.5;
01273        * if (t < 0.0)
01274        * t = -t; */
01275       EGlpNumFloor (t, x[i]);
01276       EGlpNumSubTo (t, x[i]);
01277       EGlpNumSign (t);
01278       EGlpNumMultUiTo (t, 2);
01279       EGlpNumSubTo (t, oneLpNum);
01280       if (EGlpNumIsLessZero (t))
01281         EGlpNumSign (t);
01282       /*if (t < (0.5 - ILL_INTTOL)) */
01283       if (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL))
01284       {
01285         candidatelist[ncand] = i;
01286         EGlpNumDivUiTo (t, 2);
01287         EGlpNumCopy (tval[ncand++], t);
01288       }
01289     }
01290   }
01291 
01292   if (ncand > 0)
01293   {
01294     if (ncand > maxtrys)
01295     {
01296       ILL_SAFE_MALLOC (perm, ncand, int);
01297 
01298       for (i = 0; i < ncand; i++)
01299       {
01300         perm[i] = i;
01301       }
01302       ILLutil_EGlpNum_rselect (perm, 0, ncand - 1, maxtrys, tval, &rstate);
01303 
01304       ILL_SAFE_MALLOC (newlist, maxtrys, int);
01305 
01306       for (i = 0; i < maxtrys; i++)
01307       {
01308         newlist[i] = candidatelist[perm[i]];
01309       }
01310       ILL_IFFREE (candidatelist, int);
01311 
01312       candidatelist = newlist;
01313       newlist = 0;
01314       ncand = maxtrys;
01315     }
01316 
01317     downpen = EGlpNumAllocArray (ncand);
01318     uppen = EGlpNumAllocArray (ncand);
01319     xlist = EGlpNumAllocArray (ncand);
01320 
01321     for (i = 0; i < ncand; i++)
01322     {
01323       EGlpNumCopy (xlist[i], x[candidatelist[i]]);
01324     }
01325 
01326     rval = ILLlib_strongbranch (lp, pinf, candidatelist, ncand,
01327                                 0, downpen, uppen, STRONG_PIVOTS,
01328                                 ILL_MAXDOUBLE, itcnt);
01329     ILL_CLEANUP_IF (rval);
01330 
01331     for (i = 0; i < ncand; i++)
01332     {
01333       /*t = ILL_BRANCH_STRONG_VAL (downpen[i], uppen[i]); */
01334       if (EGlpNumIsLess (downpen[i], uppen[i]))
01335       {
01336         EGlpNumCopy (t, downpen[i]);
01337         EGlpNumMultUiTo (t, ILL_BRANCH_STRONG_WEIGHT);
01338         EGlpNumAddTo (t, uppen[i]);
01339       }
01340       else
01341       {
01342         EGlpNumCopy (t, uppen[i]);
01343         EGlpNumMultUiTo (t, ILL_BRANCH_STRONG_WEIGHT);
01344         EGlpNumAddTo (t, downpen[i]);
01345       }
01346       EGlpNumDivUiTo (t, ILL_BRANCH_STRONG_WEIGHT + 1);
01347       if (EGlpNumIsLess (tbest, t))
01348       {
01349         EGlpNumCopy (tbest, t);
01350         ibest = candidatelist[i];
01351       }
01352     }
01353   }
01354 
01355   *bvar = ibest;
01356 
01357 
01358 CLEANUP:
01359 
01360   EGlpNumClearVar (t);
01361   EGlpNumClearVar (tbest);
01362   EGlpNumFreeArray (tval);
01363   EGlpNumFreeArray (xlist);
01364   EGlpNumFreeArray (uppen);
01365   EGlpNumFreeArray (downpen);
01366   ILL_IFFREE (candidatelist, int);
01367   ILL_IFFREE (newlist, int);
01368   ILL_IFFREE (perm, int);
01369 
01370   ILL_RETURN (rval, "find_strong_branch");
01371 }
01372 
01373 static void check_integral (
01374   lpinfo * lp,
01375   EGlpNum_t * x,
01376   int *yesno)
01377 {
01378   int i;
01379   EGlpNum_t t;
01380   ILLlpdata *qlp = lp->O;
01381 
01382   EGlpNumInitVar (t);
01383 
01384   for (i = 0; i < qlp->nstruct; i++)
01385   {
01386     if (qlp->intmarker[i])
01387     {
01388       /*t = ILLutil_our_frac (x[i]); */
01389       EGlpNumFloor (t, x[i]);
01390       EGlpNumSubTo (t, x[i]);
01391       EGlpNumSign (t);
01392       /*if (t > ILL_INTTOL && t < 1.0 - ILL_INTTOL) */
01393       if ((EGlpNumIsNeqZero (t, ILL_INTTOL)) &&
01394           (EGlpNumIsNeq (t, oneLpNum, ILL_INTTOL)))
01395       {
01396         *yesno = 0;
01397         EGlpNumClearVar (t);
01398         return;
01399       }
01400     }
01401   }
01402 
01403   *yesno = 1;
01404   EGlpNumClearVar (t);
01405 }
01406 
01407 static int plunge (
01408   mipinfo * minf,
01409   itcnt_t*itcnt)
01410 {
01411   int rval = 0;
01412   int i, status;
01413   lpinfo *lp = minf->lp;
01414   ILLlpdata *qlp = minf->lp->O;
01415   EGlpNum_t *oldlower = 0;
01416   EGlpNum_t *oldupper = 0;
01417 
01418   if (minf->watch)
01419   {
01420     printf ("Plunging ...\n");
01421     fflush (stdout);
01422   }
01423 
01424   oldlower = EGlpNumAllocArray (qlp->nstruct);
01425   oldupper = EGlpNumAllocArray (qlp->nstruct);
01426 
01427   for (i = 0; i < qlp->nstruct; i++)
01428   {
01429     EGlpNumCopy (oldlower[i], minf->lower[i]);
01430     EGlpNumCopy (oldupper[i], minf->upper[i]);
01431   }
01432 
01433   rval = plunge_work (minf, 0, itcnt);
01434   ILL_CLEANUP_IF (rval);
01435 
01436   for (i = 0; i < qlp->nstruct; i++)
01437   {
01438     rval = ILLlib_chgbnd (lp, i, 'L', oldlower[i]);
01439     ILL_CLEANUP_IF (rval);
01440     rval = ILLlib_chgbnd (lp, i, 'U', oldupper[i]);
01441     ILL_CLEANUP_IF (rval);
01442     EGlpNumCopy (minf->lower[i], oldlower[i]);
01443     EGlpNumCopy (minf->upper[i], oldupper[i]);
01444   }
01445 
01446   rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01447   ILL_CLEANUP_IF (rval);
01448 
01449 
01450 CLEANUP:
01451 
01452   EGlpNumFreeArray (oldlower);
01453   EGlpNumFreeArray (oldupper);
01454 
01455   ILL_RETURN (rval, "plunge");
01456 }
01457 
01458 static int plunge_work (
01459   mipinfo * minf,
01460   int depth,
01461   itcnt_t*itcnt)
01462 {
01463   int rval = 0;
01464   int bvar, status, count;
01465   EGlpNum_t lpval, val0, val1, int_tol;
01466   lpinfo *lp = minf->lp;
01467 
01468   EGlpNumInitVar (lpval);
01469   EGlpNumInitVar (val0);
01470   EGlpNumInitVar (val1);
01471   EGlpNumInitVar (int_tol);
01472   EGlpNumSet (int_tol, 0.001);
01473 
01474   rval = ILLlib_get_x (lp, 0, minf->x);
01475   ILL_CLEANUP_IF (rval);
01476 
01477   rval = round_variables (minf, &count, &int_tol /* 0.001 */ );
01478   ILL_CLEANUP_IF (rval);
01479   if (count)
01480   {
01481     rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01482     ILL_CLEANUP_IF (rval);
01483     if (status != QS_LP_OPTIMAL)
01484     {
01485       goto CLEANUP;
01486     }
01487     rval = ILLlib_get_x (lp, 0, minf->x);
01488     ILL_CLEANUP_IF (rval);
01489   }
01490 
01491   find_middle_branch (lp, minf->x, &bvar);
01492   if (bvar == -1)
01493   {
01494     rval = ILLlib_objval (lp, 0, &lpval);
01495     ILL_CLEANUP_IF (rval);
01496 
01497     if (EGlpNumIsLess (lpval, minf->value))
01498     {
01499       printf ("Plunge Integral Solution: %.6f (Depth: %d)\n",
01500               EGlpNumToLf (lpval), depth);
01501       fflush (stdout);
01502 
01503       EGlpNumCopy (minf->value, lpval);
01504       EGlpNumCopyDiff (minf->objectivebound, lpval, ILL_INTTOL);
01505       copy_x (lp->O->nstruct, minf->x, minf->bestx);
01506     }
01507     goto CLEANUP;
01508   }
01509 
01510   EGlpNumOne (minf->lower[bvar]);
01511   rval = ILLlib_chgbnd (lp, bvar, 'L', oneLpNum);
01512   ILL_CLEANUP_IF (rval);
01513   rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01514   ILL_CLEANUP_IF (rval);
01515 
01516   if (status == QS_LP_UNSOLVED)
01517   {
01518     printf ("Simplex did not solve the plunge LP\n");
01519     fflush (stdout);
01520     rval = 1;
01521     ILL_CLEANUP;
01522   }
01523   else if (status == QS_LP_INFEASIBLE)
01524   {
01525     EGlpNumCopy (val1, ILL_MAXDOUBLE);
01526   }
01527   else if (status == QS_LP_OPTIMAL)
01528   {
01529     rval = ILLlib_objval (lp, 0, &val1);
01530     ILL_CLEANUP_IF (rval);
01531   }
01532   else
01533   {
01534     ILL_CLEANUP;
01535   }
01536 
01537   rval = ILLlib_chgbnd (lp, bvar, 'L', zeroLpNum);
01538   ILL_CLEANUP_IF (rval);
01539   EGlpNumZero (minf->lower[bvar]);
01540 
01541   EGlpNumZero (minf->upper[bvar]);
01542   rval = ILLlib_chgbnd (lp, bvar, 'U', zeroLpNum);
01543   ILL_CLEANUP_IF (rval);
01544   rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01545   ILL_CLEANUP_IF (rval);
01546 
01547   if (status == QS_LP_UNSOLVED)
01548   {
01549     printf ("Simplex did not solve the plunge LP\n");
01550     fflush (stdout);
01551     rval = 1;
01552     ILL_CLEANUP;
01553   }
01554   else if (status == QS_LP_INFEASIBLE)
01555   {
01556     EGlpNumCopy (val0, ILL_MAXDOUBLE);
01557   }
01558   else if (status == QS_LP_OPTIMAL)
01559   {
01560     rval = ILLlib_objval (lp, 0, &val0);
01561     ILL_CLEANUP_IF (rval);
01562   }
01563   else
01564   {
01565     ILL_CLEANUP;
01566   }
01567 
01568   rval = ILLlib_chgbnd (lp, bvar, 'U', oneLpNum);
01569   ILL_CLEANUP_IF (rval);
01570   EGlpNumCopy (minf->upper[bvar], oneLpNum);
01571 
01572   if (EGlpNumIsEqqual (val0, ILL_MAXDOUBLE) &&
01573       EGlpNumIsEqqual (val1, ILL_MAXDOUBLE))
01574   {
01575     ILL_CLEANUP;
01576   }
01577 
01578   if (EGlpNumIsLess (val0, val1))
01579   {
01580     EGlpNumZero (minf->upper[bvar]);
01581     rval = ILLlib_chgbnd (lp, bvar, 'U', zeroLpNum);
01582     ILL_CLEANUP_IF (rval);
01583     rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01584     ILL_CLEANUP_IF (rval);
01585     rval = plunge_work (minf, depth + 1, itcnt);
01586     ILL_CLEANUP_IF (rval);
01587     rval = ILLlib_chgbnd (lp, bvar, 'U', oneLpNum);
01588     ILL_CLEANUP_IF (rval);
01589     EGlpNumOne (minf->upper[bvar]);
01590   }
01591   else
01592   {
01593     EGlpNumOne (minf->lower[bvar]);
01594     rval = ILLlib_chgbnd (lp, bvar, 'L', oneLpNum);
01595     ILL_CLEANUP_IF (rval);
01596     rval = ILLlib_optimize (lp, 0, minf->pinf, DUAL_SIMPLEX, &status, 0, itcnt);
01597     ILL_CLEANUP_IF (rval);
01598     rval = plunge_work (minf, depth + 1, itcnt);
01599     ILL_CLEANUP_IF (rval);
01600     rval = ILLlib_chgbnd (lp, bvar, 'L', zeroLpNum);
01601     ILL_CLEANUP_IF (rval);
01602     EGlpNumZero (minf->lower[bvar]);
01603   }
01604 
01605 CLEANUP:
01606 
01607   EGlpNumClearVar (lpval);
01608   EGlpNumClearVar (val0);
01609   EGlpNumClearVar (val1);
01610   EGlpNumClearVar (int_tol);
01611   ILL_RETURN (rval, "plunge_work");
01612 }
01613 
01614 static int round_variables (
01615   mipinfo * minf,
01616   int *count,
01617   EGlpNum_t * tol)
01618 {
01619   int rval = 0;
01620   int i, hit = 0;
01621   lpinfo *lp = minf->lp;
01622   ILLlpdata *qlp = lp->O;
01623 
01624   *count = 0;
01625 
01626   for (i = 0; i < qlp->nstruct; i++)
01627   {
01628     if (qlp->intmarker[i])
01629     {
01630       if (EGlpNumIsNeqq (minf->lower[i], minf->upper[i]))
01631       {
01632         if (EGlpNumIsLess (minf->x[i], *tol))
01633         {
01634           EGlpNumZero (minf->upper[i]);
01635           rval = ILLlib_chgbnd (lp, i, 'U', zeroLpNum);
01636           ILL_CLEANUP_IF (rval);
01637           hit++;
01638         }
01639         else if (EGlpNumIsEqual (minf->x[i], oneLpNum, *tol))
01640         {
01641           EGlpNumOne (minf->lower[i]);
01642           rval = ILLlib_chgbnd (lp, i, 'L', oneLpNum);
01643           ILL_CLEANUP_IF (rval);
01644           hit++;
01645         }
01646       }
01647     }
01648   }
01649   *count = hit;
01650 
01651 CLEANUP:
01652 
01653   ILL_RETURN (rval, "round_variables");
01654 }
01655 
01656 static void copy_x (
01657   int nstruct,
01658   EGlpNum_t * from_x,
01659   EGlpNum_t * to_x)
01660 {
01661   int j;
01662 
01663   for (j = 0; j < nstruct; j++)
01664   {
01665     EGlpNumCopy (to_x[j], from_x[j]);
01666   }
01667 }
01668 
01669 static void init_mipinfo (
01670   mipinfo * minf)
01671 {
01672   if (minf)
01673   {
01674     minf->depth = 0;
01675     minf->totalnodes = 0;
01676     minf->activenodes = 0;
01677     minf->totalpivots = 0;
01678     minf->lastpivots = 0;
01679     minf->downpen = 0;
01680     minf->uppen = 0;
01681     minf->x = 0;
01682     minf->bestx = 0;
01683     minf->lower = 0;
01684     minf->upper = 0;
01685     minf->lp = 0;
01686     minf->pinf = 0;
01687     minf->head_bbnode.prev = 0;
01688     minf->head_bbnode.next = 0;
01689     minf->que = 0;
01690     minf->branching_rule = /* MIDDLEBRANCH */ STRONGBRANCH;
01691     minf->watch = 1;
01692     EGlpNumInitVar (minf->objectivebound);
01693     EGlpNumInitVar (minf->value);
01694     EGlpNumCopy (minf->objectivebound, ILL_MAXDOUBLE);
01695     EGlpNumCopy (minf->value, ILL_MAXDOUBLE);
01696     ILLptrworld_init (&minf->ptrworld);
01697   }
01698 }
01699 
01700 static void free_mipinfo (
01701   mipinfo * minf)
01702 {
01703   int total, onlist;
01704 
01705   if (minf)
01706   {
01707     EGlpNumFreeArray (minf->downpen);
01708     EGlpNumFreeArray (minf->uppen);
01709     EGlpNumFreeArray (minf->x);
01710     EGlpNumFreeArray (minf->bestx);
01711     EGlpNumFreeArray (minf->lower);
01712     EGlpNumFreeArray (minf->upper);
01713     bbnode_listfree (&minf->ptrworld, minf->head_bbnode.next);
01714     if (bbnode_check_leaks (&minf->ptrworld, &total, &onlist))
01715     {
01716       fprintf (stderr, "WARNING: %d outstanding bbnodes\n", total - onlist);
01717     }
01718     ILLptrworld_delete (&minf->ptrworld);
01719     EGlpNumClearVar ((minf->objectivebound));
01720     EGlpNumClearVar ((minf->value));
01721     memset (minf, 0, sizeof (mipinfo));
01722     //init_mipinfo (minf);
01723   }
01724 }
01725 
01726 static void init_bbnode (
01727   bbnode * b)
01728 {
01729   if (b)
01730   {
01731     b->next = 0;
01732     b->prev = 0;
01733     b->id = 0;
01734     b->depth = 0;
01735     b->handle = 0;
01736     b->cstat = 0;
01737     b->rstat = 0;
01738     b->rownorms = 0;
01739     b->bound_cnt = 0;
01740     b->bound_indx = 0;
01741     b->lu = 0;
01742     b->bounds = 0;
01743     EGlpNumInitVar ((b->bound));
01744     EGlpNumCopy (b->bound, ILL_MINDOUBLE);
01745   }
01746 }
01747 
01748 static void free_bbnode (
01749   bbnode * b)
01750 {
01751   if (b)
01752   {
01753     EGlpNumFreeArray (b->rownorms);
01754     EGlpNumFreeArray (b->bounds);
01755     ILL_IFFREE (b->cstat, char);
01756     ILL_IFFREE (b->rstat, char);
01757     ILL_IFFREE (b->bound_indx, int);
01758     ILL_IFFREE (b->lu, char);
01759 
01760     EGlpNumClearVar ((b->bound));
01761     memset (b, 0, sizeof (bbnode));
01762   }
01763 }

Generated on Wed Apr 22 09:16:09 2009 for QSopt_ex by  doxygen 1.5.2