/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecRandrounding) /*lint --e{715}*/
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_Bool propagate;

   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DIDNOTRUN;

   /* only call heuristic, if an optimal LP solution is at hand or if relaxation solution is available */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL && ! SCIPisRelaxSolValid(scip) )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* get heuristic data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* don't call heuristic, if we have already processed the current LP solution but no relaxation solution is available */
   if ( SCIPgetNLPs(scip) == heurdata->lastlp && ! SCIPisRelaxSolValid(scip) )
      return SCIP_OKAY;

   propagate = (!heurdata->propagateonlyroot || SCIPgetDepth(scip) == 0);

   /* try to round LP solution */
   SCIP_CALL( performLPRandRounding(scip, heurdata, heurtiming, propagate, result) );

   return SCIP_OKAY;
}
/** branching execution method for fractional LP solutions */
static
SCIP_DECL_BRANCHEXECLP(branchExeclpLeastinf)
{  /*lint --e{715}*/
   SCIP_VAR** lpcands;
   SCIP_Real* lpcandsfrac;
   int nlpcands;
   SCIP_Real infeasibility;
   SCIP_Real score;
   SCIP_Real obj;
   SCIP_Real bestscore;
   SCIP_Real bestobj;
   int bestcand;
   int i;

   assert(branchrule != NULL);
   assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
   assert(scip != NULL);
   assert(result != NULL);

   SCIPdebugMessage("Execlp method of leastinf branching\n");

   /* get branching candidates */
   SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, &lpcandsfrac, NULL, &nlpcands, NULL) );
   assert(nlpcands > 0);

   /* search the least infeasible candidate */
   bestscore = SCIP_REAL_MIN;
   bestobj = 0.0;
   bestcand = -1;
   for( i = 0; i < nlpcands; ++i )
   {
      assert(lpcands[i] != NULL);

      infeasibility = lpcandsfrac[i];
      infeasibility = MIN(infeasibility, 1.0-infeasibility);
      score = 1.0 - infeasibility;
      score *= SCIPvarGetBranchFactor(lpcands[i]);
      obj = SCIPvarGetObj(lpcands[i]);
      obj = REALABS(obj);
      if( SCIPisGT(scip, score, bestscore)
         || (SCIPisGE(scip, score, bestscore) && obj > bestobj) )
      {
         bestscore = score;
         bestobj = obj;
         bestcand = i;
      }
   }
   assert(bestcand >= 0);

   SCIPdebugMessage(" -> %d candidates, selected candidate %d: variable <%s> (frac=%g, obj=%g, factor=%g, score=%g)\n",
      nlpcands, bestcand, SCIPvarGetName(lpcands[bestcand]), lpcandsfrac[bestcand], bestobj,
      SCIPvarGetBranchFactor(lpcands[bestcand]), bestscore);

   /* perform the branching */
   SCIP_CALL( SCIPbranchVar(scip, lpcands[bestcand], NULL, NULL, NULL) );
   *result = SCIP_BRANCHED;

   return SCIP_OKAY;
}
/** find variable aggregations for downlock case */
static
SCIP_RETCODE findDownlockAggregations(
   SCIP*                 scip,               /**< SCIP main data structure */
   SCIPMILPMATRIX*       matrix,             /**< constraint matrix */
   int*                  nvaragg,            /**< number of redundant variables */
   AGGRTYPE*             aggtypes,           /**< type of aggregations (in same order as variables in matrix) */
   SCIP_VAR**            binvars             /**< pointers to the binary variables (in same order as variables in matrix) */
   )
{
   int nvars;
   int i;

   assert(scip != NULL);
   assert(matrix != NULL);
   assert(nvaragg != NULL);
   assert(aggtypes != NULL);
   assert(binvars != NULL);

   nvars = SCIPmatrixGetNColumns(matrix);

   for( i = 0; i < nvars; i++ )
   {
      /* column has only one downlock which keeps it from being fixed by duality fixing;
       * only handle variable if it was not yet aggregated due to a single uplock
       */
      if( SCIPmatrixGetColNDownlocks(matrix, i) == 1 &&
         SCIPisGE(scip, SCIPvarGetObj(SCIPmatrixGetVar(matrix, i)), 0.0) &&
         aggtypes[i] == NOAGG )
      {
         SCIP_Real lb;
         SCIP_Real ub;

         lb = SCIPmatrixGetColLb(matrix, i);
         ub = SCIPmatrixGetColUb(matrix, i);
         assert(lb == SCIPvarGetLbGlobal(SCIPmatrixGetVar(matrix, i))); /*lint !e777*/
         assert(ub == SCIPvarGetUbGlobal(SCIPmatrixGetVar(matrix, i))); /*lint !e777*/

         /* the variable needs to have finite bounds to allow an agregation */
         if( !SCIPisInfinity(scip, -lb) && !SCIPisInfinity(scip, ub) )
         {
            int binvaridx;
            AGGRTYPE aggtype;
            getBinVarIdxInDownlockRow(scip, matrix, i, &binvaridx, &aggtype);

            if( binvaridx >= 0 )
            {
               aggtypes[i] = aggtype;
               binvars[i] = SCIPmatrixGetVar(matrix, binvaridx);
               (*nvaragg)++;
            }
         }
      }
   }

   return SCIP_OKAY;
}
/** perform randomized LP-rounding */
static
SCIP_RETCODE performLPRandRounding(
   SCIP*                 scip,               /**< SCIP main data structure */
   SCIP_HEURDATA*        heurdata,           /**< heuristic data */
   SCIP_HEURTIMING       heurtiming,         /**< heuristic timing mask */
   SCIP_Bool             propagate,          /**< should the heuristic apply SCIP's propagation? */
   SCIP_RESULT*          result              /**< pointer to store the result of the heuristic call */
   )
{
   SCIP_SOL* sol;
   SCIP_VAR** lpcands;
   SCIP_Longint nlps;
   int nlpcands;

   /* only call heuristic, if an optimal LP solution is at hand */
   if ( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* get fractional variables, that should be integral */
   SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, NULL, &nlpcands, NULL, NULL) );

   /* only call heuristic, if LP solution is fractional; except we are called during pricing, in this case we
    * want to detect a (mixed) integer (LP) solution which is primal feasible */
   if ( nlpcands == 0  && heurtiming != SCIP_HEURTIMING_DURINGPRICINGLOOP )
      return SCIP_OKAY;

   /* get the working solution from heuristic's local data */
   sol = heurdata->sol;
   assert( sol != NULL );

   /* copy the current LP solution to the working solution */
   SCIP_CALL( SCIPlinkLPSol(scip, sol) );

   /* don't call heuristic, if we have already processed the current LP solution */
   nlps = SCIPgetNLPs(scip);
   if( nlps == heurdata->lastlp )
      return SCIP_OKAY;
   heurdata->lastlp = nlps;

   *result = SCIP_DIDNOTFIND;

   /* perform random rounding */
   SCIPdebugMessage("executing rand LP-rounding heuristic: %d fractionals\n", nlpcands);
   SCIP_CALL( performRandRounding(scip, heurdata, sol, lpcands, nlpcands, propagate, result) );

   return SCIP_OKAY;
}
Exemple #5
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecIntdiving) /*lint --e{715}*/
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_LPSOLSTAT lpsolstat;
   SCIP_VAR** pseudocands;
   SCIP_VAR** fixcands;
   SCIP_Real* fixcandscores;
   SCIP_Real searchubbound;
   SCIP_Real searchavgbound;
   SCIP_Real searchbound;
   SCIP_Real objval;
   SCIP_Bool lperror;
   SCIP_Bool cutoff;
   SCIP_Bool backtracked;
   SCIP_Longint ncalls;
   SCIP_Longint nsolsfound;
   SCIP_Longint nlpiterations;
   SCIP_Longint maxnlpiterations;
   int nfixcands;
   int nbinfixcands;
   int depth;
   int maxdepth;
   int maxdivedepth;
   int divedepth;
   int nextcand;
   int c;

   assert(heur != NULL);
   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(scip != NULL);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DELAYED;

   /* do not call heuristic of node was already detected to be infeasible */
   if( nodeinfeasible )
      return SCIP_OKAY;

   /* only call heuristic, if an optimal LP solution is at hand */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
   if( !SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* don't dive two times at the same node */
   if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
      return SCIP_OKAY;

   *result = SCIP_DIDNOTRUN;

   /* get heuristic's data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
   depth = SCIPgetDepth(scip);
   maxdepth = SCIPgetMaxDepth(scip);
   maxdepth = MAX(maxdepth, 100);
   if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
      return SCIP_OKAY;

   /* calculate the maximal number of LP iterations until heuristic is aborted */
   nlpiterations = SCIPgetNNodeLPIterations(scip);
   ncalls = SCIPheurGetNCalls(heur);
   nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
   maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
   maxnlpiterations += heurdata->maxlpiterofs;

   /* don't try to dive, if we took too many LP iterations during diving */
   if( heurdata->nlpiterations >= maxnlpiterations )
      return SCIP_OKAY;

   /* allow at least a certain number of LP iterations in this dive */
   maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);

   /* get unfixed integer variables */
   SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, &nfixcands, NULL) );

   /* don't try to dive, if there are no fractional variables */
   if( nfixcands == 0 )
      return SCIP_OKAY;

   /* calculate the objective search bound */
   if( SCIPgetNSolsFound(scip) == 0 )
   {
      if( heurdata->maxdiveubquotnosol > 0.0 )
         searchubbound = SCIPgetLowerbound(scip)
            + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
      else
         searchubbound = SCIPinfinity(scip);
      if( heurdata->maxdiveavgquotnosol > 0.0 )
         searchavgbound = SCIPgetLowerbound(scip)
            + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
      else
         searchavgbound = SCIPinfinity(scip);
   }
   else
   {
      if( heurdata->maxdiveubquot > 0.0 )
         searchubbound = SCIPgetLowerbound(scip)
            + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
      else
         searchubbound = SCIPinfinity(scip);
      if( heurdata->maxdiveavgquot > 0.0 )
         searchavgbound = SCIPgetLowerbound(scip)
            + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
      else
         searchavgbound = SCIPinfinity(scip);
   }
   searchbound = MIN(searchubbound, searchavgbound);
   if( SCIPisObjIntegral(scip) )
      searchbound = SCIPceil(scip, searchbound);

   /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
   maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
   maxdivedepth = MIN(maxdivedepth, maxdepth);
   maxdivedepth *= 10;

   *result = SCIP_DIDNOTFIND;

   /* start diving */
   SCIP_CALL( SCIPstartProbing(scip) );

   /* enables collection of variable statistics during probing */
   SCIPenableVarHistory(scip);

   SCIPdebugMessage("(node %" SCIP_LONGINT_FORMAT ") executing intdiving heuristic: depth=%d, %d non-fixed, dualbound=%g, searchbound=%g\n",
      SCIPgetNNodes(scip), SCIPgetDepth(scip), nfixcands, SCIPgetDualbound(scip), SCIPretransformObj(scip, searchbound));

   /* copy the pseudo candidates into own array, because we want to reorder them */
   SCIP_CALL( SCIPduplicateBufferArray(scip, &fixcands, pseudocands, nfixcands) );

   /* sort non-fixed variables by non-increasing inference score, but prefer binaries over integers in any case */
   SCIP_CALL( SCIPallocBufferArray(scip, &fixcandscores, nfixcands) );
   nbinfixcands = 0;
   for( c = 0; c < nfixcands; ++c )
   {
      SCIP_VAR* var;
      SCIP_Real score;
      int colveclen;
      int left;
      int right;
      int i;

      assert(c >= nbinfixcands);
      var = fixcands[c];
      assert(SCIPvarIsIntegral(var));
      colveclen = (SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN ? SCIPcolGetNNonz(SCIPvarGetCol(var)) : 0);
      if( SCIPvarIsBinary(var) )
      {
         score = 500.0 * SCIPvarGetNCliques(var, TRUE) + 100.0 * SCIPvarGetNImpls(var, TRUE)
            + SCIPgetVarAvgInferenceScore(scip, var) + (SCIP_Real)colveclen/100.0;

         /* shift the non-binary variables one slot to the right */
         for( i = c; i > nbinfixcands; --i )
         {
            fixcands[i] = fixcands[i-1];
            fixcandscores[i] = fixcandscores[i-1];
         }
         /* put the new candidate into the first nbinfixcands slot */
         left = 0;
         right = nbinfixcands;
         nbinfixcands++;
      }
      else
      {
         score = 5.0 * (SCIPvarGetNCliques(var, FALSE) + SCIPvarGetNCliques(var, TRUE))
            + SCIPvarGetNImpls(var, FALSE) + SCIPvarGetNImpls(var, TRUE) + SCIPgetVarAvgInferenceScore(scip, var)
            + (SCIP_Real)colveclen/10000.0;

         /* put the new candidate in the slots after the binary candidates */
         left = nbinfixcands;
         right = c;
      }
      for( i = right; i > left && score > fixcandscores[i-1]; --i )
      {
         fixcands[i] = fixcands[i-1];
         fixcandscores[i] = fixcandscores[i-1];
      }
      fixcands[i] = var;
      fixcandscores[i] = score;
      SCIPdebugMessage("  <%s>: ncliques=%d/%d, nimpls=%d/%d, inferencescore=%g, colveclen=%d  ->  score=%g\n",
         SCIPvarGetName(var), SCIPvarGetNCliques(var, FALSE), SCIPvarGetNCliques(var, TRUE),
         SCIPvarGetNImpls(var, FALSE), SCIPvarGetNImpls(var, TRUE), SCIPgetVarAvgInferenceScore(scip, var),
         colveclen, score);
   }
   SCIPfreeBufferArray(scip, &fixcandscores);

   /* get LP objective value */
   lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
   objval = SCIPgetLPObjval(scip);

   /* dive as long we are in the given objective, depth and iteration limits, but if possible, we dive at least with
    * the depth 10
    */
   lperror = FALSE;
   cutoff = FALSE;
   divedepth = 0;
   nextcand = 0;
   while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL
      && (divedepth < 10
         || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
      && !SCIPisStopped(scip) )
   {
      SCIP_VAR* var;
      SCIP_Real bestsolval;
      SCIP_Real bestfixval;
      int bestcand;
      SCIP_Longint nnewlpiterations;
      SCIP_Longint nnewdomreds;

      /* open a new probing node if this will not exceed the maximal tree depth, otherwise stop here */
      if( SCIPgetDepth(scip) < SCIPgetDepthLimit(scip) )
      {
         SCIP_CALL( SCIPnewProbingNode(scip) );
         divedepth++;
      }
      else
         break;

      nnewlpiterations = 0;
      nnewdomreds = 0;

      /* fix binary variable that is closest to 1 in the LP solution to 1;
       * if all binary variables are fixed, fix integer variable with least fractionality in LP solution
       */
      bestcand = -1;
      bestsolval = -1.0;
      bestfixval = 1.0;

      /* look in the binary variables for fixing candidates */
      for( c = nextcand; c < nbinfixcands; ++c )
      {
         SCIP_Real solval;

         var = fixcands[c];

         /* ignore already fixed variables */
         if( var == NULL )
            continue;
         if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
         {
            fixcands[c] = NULL;
            continue;
         }

         /* get the LP solution value */
         solval = SCIPvarGetLPSol(var);

         if( solval > bestsolval )
         {
            bestcand = c;
            bestfixval = 1.0;
            bestsolval = solval;
            if( SCIPisGE(scip, bestsolval, 1.0) )
            {
               /* we found an unfixed binary variable with LP solution value of 1.0 - there cannot be a better candidate */
               break;
            }
            else if( SCIPisLE(scip, bestsolval, 0.0) )
            {
               /* the variable is currently at 0.0 - this is the only situation where we want to fix it to 0.0 */
               bestfixval = 0.0;
            }
         }
      }

      /* if all binary variables are fixed, look in the integer variables for a fixing candidate */
      if( bestcand == -1 )
      {
         SCIP_Real bestfrac;

         bestfrac = SCIP_INVALID;
         for( c = MAX(nextcand, nbinfixcands); c < nfixcands; ++c )
         {
            SCIP_Real solval;
            SCIP_Real frac;

            var = fixcands[c];

            /* ignore already fixed variables */
            if( var == NULL )
               continue;
            if( SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) < 0.5 )
            {
               fixcands[c] = NULL;
               continue;
            }

            /* get the LP solution value */
            solval = SCIPvarGetLPSol(var);
            frac = SCIPfrac(scip, solval);

            /* ignore integer variables that are currently integral */
            if( SCIPisFeasFracIntegral(scip, frac) )
               continue;

            if( frac < bestfrac )
            {
               bestcand = c;
               bestsolval = solval;
               bestfrac = frac;
               bestfixval = SCIPfloor(scip, bestsolval + 0.5);
               if( SCIPisZero(scip, bestfrac) )
               {
                  /* we found an unfixed integer variable with integral LP solution value */
                  break;
               }
            }
         }
      }
      assert(-1 <= bestcand && bestcand < nfixcands);

      /* if there is no unfixed candidate left, we are done */
      if( bestcand == -1 )
         break;

      var = fixcands[bestcand];
      assert(var != NULL);
      assert(SCIPvarIsIntegral(var));
      assert(SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var) > 0.5);
      assert(SCIPisGE(scip, bestfixval, SCIPvarGetLbLocal(var)));
      assert(SCIPisLE(scip, bestfixval, SCIPvarGetUbLocal(var)));

      backtracked = FALSE;
      do
      {
         /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
          * occured or variable was fixed by propagation while backtracking => Abort diving!
          */
         if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
         {
            SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g], diving aborted \n",
               SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var));
            cutoff = TRUE;
            break;
         }
         if( SCIPisFeasLT(scip, bestfixval, SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, bestfixval, SCIPvarGetUbLocal(var)) )
         {
            SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
               SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
            assert(backtracked);
            break;
         }

         /* apply fixing of best candidate */
         SCIPdebugMessage("  dive %d/%d, LP iter %" SCIP_LONGINT_FORMAT "/%" SCIP_LONGINT_FORMAT ", %d unfixed: var <%s>, sol=%g, oldbounds=[%g,%g], fixed to %g\n",
            divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations, SCIPgetNPseudoBranchCands(scip),
            SCIPvarGetName(var), bestsolval, SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), bestfixval);
         SCIP_CALL( SCIPfixVarProbing(scip, var, bestfixval) );

         /* apply domain propagation */
         SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, &nnewdomreds) );
         if( !cutoff )
         {
            /* if the best candidate was just fixed to its LP value and no domain reduction was found, the LP solution
             * stays valid, and the LP does not need to be resolved
             */
            if( nnewdomreds > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
            {
            /* resolve the diving LP */
               /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
                * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
                */
#ifdef NDEBUG
               SCIP_RETCODE retstat;
               nlpiterations = SCIPgetNLPIterations(scip);
               retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
               if( retstat != SCIP_OKAY )
               {
                  SCIPwarningMessage(scip, "Error while solving LP in Intdiving heuristic; LP solve terminated with code <%d>\n",retstat);
               }
#else
               nlpiterations = SCIPgetNLPIterations(scip);
               SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
#endif

               if( lperror )
                  break;

               /* update iteration count */
               nnewlpiterations = SCIPgetNLPIterations(scip) - nlpiterations;
               heurdata->nlpiterations += nnewlpiterations;

               /* get LP solution status */
               lpsolstat = SCIPgetLPSolstat(scip);
               assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
                     (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
            }
         }

         /* perform backtracking if a cutoff was detected */
         if( cutoff && !backtracked && heurdata->backtrack )
         {
            SCIPdebugMessage("  *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
            SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );

            /* after backtracking there has to be at least one open node without exceeding the maximal tree depth */
            assert(SCIPgetDepthLimit(scip) > SCIPgetDepth(scip));

            SCIP_CALL( SCIPnewProbingNode(scip) );

            bestfixval = SCIPvarIsBinary(var)
               ? 1.0 - bestfixval
               : (SCIPisGT(scip, bestsolval, bestfixval) && SCIPisFeasLE(scip, bestfixval + 1, SCIPvarGetUbLocal(var)) ? bestfixval + 1 : bestfixval - 1);

            backtracked = TRUE;
         }
         else
            backtracked = FALSE;
      }
      while( backtracked );

      if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
      {
         SCIP_Bool success;

         /* get new objective value */
         objval = SCIPgetLPObjval(scip);

         if( nnewlpiterations > 0 || !SCIPisEQ(scip, bestsolval, bestfixval) )
         {
            /* we must start again with the first candidate, since the LP solution changed */
            nextcand = 0;

            /* create solution from diving LP and try to round it */
            SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
            SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );
            if( success )
            {
               SCIPdebugMessage("intdiving found roundable primal solution: obj=%g\n",
                  SCIPgetSolOrigObj(scip, heurdata->sol));

               /* try to add solution to SCIP */
               SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

               /* check, if solution was feasible and good enough */
               if( success )
               {
                  SCIPdebugMessage(" -> solution was feasible and good enough\n");
                  *result = SCIP_FOUNDSOL;
               }
            }
         }
         else
            nextcand = bestcand+1; /* continue with the next candidate in the following loop */
      }
      SCIPdebugMessage("   -> lpsolstat=%d, objval=%g/%g\n", lpsolstat, objval, searchbound);
   }

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &fixcands);

   /* end diving */
   SCIP_CALL( SCIPendProbing(scip) );

   if( *result == SCIP_FOUNDSOL )
      heurdata->nsuccess++;

   SCIPdebugMessage("intdiving heuristic finished\n");

   return SCIP_OKAY;
}
Exemple #6
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecActconsdiving) /*lint --e{715}*/
{   /*lint --e{715}*/
    SCIP_HEURDATA* heurdata;
    SCIP_LPSOLSTAT lpsolstat;
    SCIP_VAR* var;
    SCIP_VAR** lpcands;
    SCIP_Real* lpcandssol;
    SCIP_Real* lpcandsfrac;
    SCIP_Real searchubbound;
    SCIP_Real searchavgbound;
    SCIP_Real searchbound;
    SCIP_Real objval;
    SCIP_Real oldobjval;
    SCIP_Real frac;
    SCIP_Real bestfrac;
    SCIP_Bool bestcandmayrounddown;
    SCIP_Bool bestcandmayroundup;
    SCIP_Bool bestcandroundup;
    SCIP_Bool mayrounddown;
    SCIP_Bool mayroundup;
    SCIP_Bool roundup;
    SCIP_Bool lperror;
    SCIP_Bool cutoff;
    SCIP_Bool backtracked;
    SCIP_Longint ncalls;
    SCIP_Longint nsolsfound;
    SCIP_Longint nlpiterations;
    SCIP_Longint maxnlpiterations;
    int nlpcands;
    int startnlpcands;
    int depth;
    int maxdepth;
    int maxdivedepth;
    int divedepth;
    SCIP_Real actscore;
    SCIP_Real downscore;
    SCIP_Real upscore;
    SCIP_Real bestactscore;
    int bestcand;
    int c;

    assert(heur != NULL);
    assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    assert(scip != NULL);
    assert(result != NULL);
    assert(SCIPhasCurrentNodeLP(scip));

    *result = SCIP_DELAYED;

    /* do not call heuristic of node was already detected to be infeasible */
    if( nodeinfeasible )
        return SCIP_OKAY;

    /* only call heuristic, if an optimal LP solution is at hand */
    if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
        return SCIP_OKAY;

    /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
        return SCIP_OKAY;

    /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
    if( !SCIPisLPSolBasic(scip) )
        return SCIP_OKAY;

    /* don't dive two times at the same node */
    if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
        return SCIP_OKAY;

    *result = SCIP_DIDNOTRUN;

    /* get heuristic's data */
    heurdata = SCIPheurGetData(heur);
    assert(heurdata != NULL);

    /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
    depth = SCIPgetDepth(scip);
    maxdepth = SCIPgetMaxDepth(scip);
    maxdepth = MAX(maxdepth, 30);
    if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
        return SCIP_OKAY;

    /* calculate the maximal number of LP iterations until heuristic is aborted */
    nlpiterations = SCIPgetNNodeLPIterations(scip);
    ncalls = SCIPheurGetNCalls(heur);
    nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
    maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
    maxnlpiterations += heurdata->maxlpiterofs;

    /* don't try to dive, if we took too many LP iterations during diving */
    if( heurdata->nlpiterations >= maxnlpiterations )
        return SCIP_OKAY;

    /* allow at least a certain number of LP iterations in this dive */
    maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);

    /* get fractional variables that should be integral */
    SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );

    /* don't try to dive, if there are no fractional variables */
    if( nlpcands == 0 )
        return SCIP_OKAY;

    /* calculate the objective search bound */
    if( SCIPgetNSolsFound(scip) == 0 )
    {
        if( heurdata->maxdiveubquotnosol > 0.0 )
            searchubbound = SCIPgetLowerbound(scip)
                            + heurdata->maxdiveubquotnosol * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
        else
            searchubbound = SCIPinfinity(scip);
        if( heurdata->maxdiveavgquotnosol > 0.0 )
            searchavgbound = SCIPgetLowerbound(scip)
                             + heurdata->maxdiveavgquotnosol * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
        else
            searchavgbound = SCIPinfinity(scip);
    }
    else
    {
        if( heurdata->maxdiveubquot > 0.0 )
            searchubbound = SCIPgetLowerbound(scip)
                            + heurdata->maxdiveubquot * (SCIPgetCutoffbound(scip) - SCIPgetLowerbound(scip));
        else
            searchubbound = SCIPinfinity(scip);
        if( heurdata->maxdiveavgquot > 0.0 )
            searchavgbound = SCIPgetLowerbound(scip)
                             + heurdata->maxdiveavgquot * (SCIPgetAvgLowerbound(scip) - SCIPgetLowerbound(scip));
        else
            searchavgbound = SCIPinfinity(scip);
    }
    searchbound = MIN(searchubbound, searchavgbound);
    if( SCIPisObjIntegral(scip) )
        searchbound = SCIPceil(scip, searchbound);

    /* calculate the maximal diving depth: 10 * min{number of integer variables, max depth} */
    maxdivedepth = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
    maxdivedepth = MIN(maxdivedepth, maxdepth);
    maxdivedepth *= 10;

    *result = SCIP_DIDNOTFIND;

    /* start diving */
    SCIP_CALL( SCIPstartProbing(scip) );

    /* enables collection of variable statistics during probing */
    SCIPenableVarHistory(scip);

    /* get LP objective value */
    lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
    objval = SCIPgetLPObjval(scip);

    SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing actconsdiving heuristic: depth=%d, %d fractionals, dualbound=%g, avgbound=%g, cutoffbound=%g, searchbound=%g\n",
                     SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), SCIPgetAvgDualbound(scip),
                     SCIPretransformObj(scip, SCIPgetCutoffbound(scip)), SCIPretransformObj(scip, searchbound));

    /* dive as long we are in the given objective, depth and iteration limits and fractional variables exist, but
     * - if possible, we dive at least with the depth 10
     * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
     */
    lperror = FALSE;
    cutoff = FALSE;
    divedepth = 0;
    bestcandmayrounddown = FALSE;
    bestcandmayroundup = FALSE;
    startnlpcands = nlpcands;
    while( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
            && (divedepth < 10
                || nlpcands <= startnlpcands - divedepth/2
                || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations && objval < searchbound))
            && !SCIPisStopped(scip) )
    {
        divedepth++;
        SCIP_CALL( SCIPnewProbingNode(scip) );

        /* choose variable fixing:
         * - prefer variables that may not be rounded without destroying LP feasibility:
         *   - of these variables, round variable with least number of locks in corresponding direction
         * - if all remaining fractional variables may be rounded without destroying LP feasibility:
         *   - round variable with least number of locks in opposite of its feasible rounding direction
         */
        bestcand = -1;
        bestactscore = -1.0;
        bestfrac = SCIP_INVALID;
        bestcandmayrounddown = TRUE;
        bestcandmayroundup = TRUE;
        bestcandroundup = FALSE;
        for( c = 0; c < nlpcands; ++c )
        {
            var = lpcands[c];
            mayrounddown = SCIPvarMayRoundDown(var);
            mayroundup = SCIPvarMayRoundUp(var);
            frac = lpcandsfrac[c];
            if( mayrounddown || mayroundup )
            {
                /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
                if( bestcandmayrounddown || bestcandmayroundup )
                {
                    /* choose rounding direction:
                     * - if variable may be rounded in both directions, round corresponding to the fractionality
                     * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
                     *   the current fractional solution
                     */
                    if( mayrounddown && mayroundup )
                        roundup = (frac > 0.5);
                    else
                        roundup = mayrounddown;

                    if( roundup )
                        frac = 1.0 - frac;
                    actscore = getNActiveConsScore(scip, var, &downscore, &upscore);

                    /* penalize too small fractions */
                    if( frac < 0.01 )
                        actscore *= 0.01;

                    /* prefer decisions on binary variables */
                    if( !SCIPvarIsBinary(var) )
                        actscore *= 0.01;

                    /* check, if candidate is new best candidate */
                    assert(0.0 < frac && frac < 1.0);
                    if( SCIPisGT(scip, actscore, bestactscore) || (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) )
                    {
                        bestcand = c;
                        bestactscore = actscore;
                        bestfrac = frac;
                        bestcandmayrounddown = mayrounddown;
                        bestcandmayroundup = mayroundup;
                        bestcandroundup = roundup;
                    }
                }
            }
            else
            {
                /* the candidate may not be rounded */
                actscore = getNActiveConsScore(scip, var, &downscore, &upscore);
                roundup = (downscore < upscore);
                if( roundup )
                    frac = 1.0 - frac;

                /* penalize too small fractions */
                if( frac < 0.01 )
                    actscore *= 0.01;

                /* prefer decisions on binary variables */
                if( !SCIPvarIsBinary(var) )
                    actscore *= 0.01;

                /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
                assert(0.0 < frac && frac < 1.0);
                if( bestcandmayrounddown || bestcandmayroundup || SCIPisGT(scip, actscore, bestactscore) ||
                        (SCIPisGE(scip, actscore, bestactscore) && frac < bestfrac) )
                {
                    bestcand = c;
                    bestactscore = actscore;
                    bestfrac = frac;
                    bestcandmayrounddown = FALSE;
                    bestcandmayroundup = FALSE;
                    bestcandroundup = roundup;
                }
                assert(bestfrac < SCIP_INVALID);
            }
        }
        assert(bestcand != -1);

        /* if all candidates are roundable, try to round the solution */
        if( bestcandmayrounddown || bestcandmayroundup )
        {
            SCIP_Bool success;

            /* create solution from diving LP and try to round it */
            SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
            SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );

            if( success )
            {
                SCIPdebugMessage("actconsdiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));

                /* try to add solution to SCIP */
                SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

                /* check, if solution was feasible and good enough */
                if( success )
                {
                    SCIPdebugMessage(" -> solution was feasible and good enough\n");
                    *result = SCIP_FOUNDSOL;
                }
            }
        }
        assert(bestcand != -1);
        var = lpcands[bestcand];

        backtracked = FALSE;
        do
        {
            /* if the variable is already fixed or if the solution value is outside the domain, numerical troubles may have
             * occured or variable was fixed by propagation while backtracking => Abort diving!
             */
            if( SCIPvarGetLbLocal(var) >= SCIPvarGetUbLocal(var) - 0.5 )
            {
                SCIPdebugMessage("Selected variable <%s> already fixed to [%g,%g] (solval: %.9f), diving aborted \n",
                                 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
                cutoff = TRUE;
                break;
            }
            if( SCIPisFeasLT(scip, lpcandssol[bestcand], SCIPvarGetLbLocal(var)) || SCIPisFeasGT(scip, lpcandssol[bestcand], SCIPvarGetUbLocal(var)) )
            {
                SCIPdebugMessage("selected variable's <%s> solution value is outside the domain [%g,%g] (solval: %.9f), diving aborted\n",
                                 SCIPvarGetName(var), SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var), lpcandssol[bestcand]);
                assert(backtracked);
                break;
            }

            /* apply rounding of best candidate */
            if( bestcandroundup == !backtracked )
            {
                /* round variable up */
                SCIPdebugMessage("  dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
                                 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
                                 SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
                                 lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
                                 SCIPfeasCeil(scip, lpcandssol[bestcand]), SCIPvarGetUbLocal(var));
                SCIP_CALL( SCIPchgVarLbProbing(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
            }
            else
            {
                /* round variable down */
                SCIPdebugMessage("  dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, oldbounds=[%g,%g], newbounds=[%g,%g]\n",
                                 divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
                                 SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
                                 lpcandssol[bestcand], SCIPvarGetLbLocal(var), SCIPvarGetUbLocal(var),
                                 SCIPvarGetLbLocal(var), SCIPfeasFloor(scip, lpcandssol[bestcand]));
                SCIP_CALL( SCIPchgVarUbProbing(scip, lpcands[bestcand], SCIPfeasFloor(scip, lpcandssol[bestcand])) );
            }

            /* apply domain propagation */
            SCIP_CALL( SCIPpropagateProbing(scip, 0, &cutoff, NULL) );
            if( !cutoff )
            {
                /* resolve the diving LP */
                /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
                 * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
                 */
#ifdef NDEBUG
                SCIP_RETCODE retstat;
                nlpiterations = SCIPgetNLPIterations(scip);
                retstat = SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff);
                if( retstat != SCIP_OKAY )
                {
                    SCIPwarningMessage(scip, "Error while solving LP in Actconsdiving heuristic; LP solve terminated with code <%d>\n",retstat);
                }
#else
                nlpiterations = SCIPgetNLPIterations(scip);
                SCIP_CALL( SCIPsolveProbingLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, &cutoff) );
#endif

                if( lperror )
                    break;

                /* update iteration count */
                heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;

                /* get LP solution status, objective value, and fractional variables, that should be integral */
                lpsolstat = SCIPgetLPSolstat(scip);
                assert(cutoff || (lpsolstat != SCIP_LPSOLSTAT_OBJLIMIT && lpsolstat != SCIP_LPSOLSTAT_INFEASIBLE &&
                                  (lpsolstat != SCIP_LPSOLSTAT_OPTIMAL || SCIPisLT(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)))));
            }

            /* perform backtracking if a cutoff was detected */
            if( cutoff && !backtracked && heurdata->backtrack )
            {
                SCIPdebugMessage("  *** cutoff detected at level %d - backtracking\n", SCIPgetProbingDepth(scip));
                SCIP_CALL( SCIPbacktrackProbing(scip, SCIPgetProbingDepth(scip)-1) );
                SCIP_CALL( SCIPnewProbingNode(scip) );
                backtracked = TRUE;
            }
            else
                backtracked = FALSE;
        }
        while( backtracked );

        if( !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
        {
            /* get new objective value */
            oldobjval = objval;
            objval = SCIPgetLPObjval(scip);

            /* update pseudo cost values */
            if( SCIPisGT(scip, objval, oldobjval) )
            {
                if( bestcandroundup )
                {
                    SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 1.0-lpcandsfrac[bestcand],
                                                       objval - oldobjval, 1.0) );
                }
                else
                {
                    SCIP_CALL( SCIPupdateVarPseudocost(scip, lpcands[bestcand], 0.0-lpcandsfrac[bestcand],
                                                       objval - oldobjval, 1.0) );
                }
            }

            /* get new fractional variables */
            SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
        }
        SCIPdebugMessage("   -> lpsolstat=%d, objval=%g/%g, nfrac=%d\n", lpsolstat, objval, searchbound, nlpcands);
    }

    /* check if a solution has been found */
    if( nlpcands == 0 && !lperror && !cutoff && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
    {
        SCIP_Bool success;

        /* create solution from diving LP */
        SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
        SCIPdebugMessage("actconsdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));

        /* try to add solution to SCIP */
        SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

        /* check, if solution was feasible and good enough */
        if( success )
        {
            SCIPdebugMessage(" -> solution was feasible and good enough\n");
            *result = SCIP_FOUNDSOL;
        }
    }

    /* end diving */
    SCIP_CALL( SCIPendProbing(scip) );

    if( *result == SCIP_FOUNDSOL )
        heurdata->nsuccess++;

    SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") finished actconsdiving heuristic: %d fractionals, dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT", objval=%g/%g, lpsolstat=%d, cutoff=%u\n",
                     SCIPgetNNodes(scip), nlpcands, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
                     SCIPretransformObj(scip, objval), SCIPretransformObj(scip, searchbound), lpsolstat, cutoff);

    return SCIP_OKAY;
}
Exemple #7
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecObjpscostdiving) /*lint --e{715}*/
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_LPSOLSTAT lpsolstat;
   SCIP_VAR* var;
   SCIP_VAR** lpcands;
   SCIP_Real* lpcandssol;
   SCIP_Real* lpcandsfrac;
   SCIP_Real primsol;
   SCIP_Real frac;
   SCIP_Real pscostquot;
   SCIP_Real bestpscostquot;
   SCIP_Real oldobj;
   SCIP_Real newobj;
   SCIP_Real objscale;
   SCIP_Bool bestcandmayrounddown;
   SCIP_Bool bestcandmayroundup;
   SCIP_Bool bestcandroundup;
   SCIP_Bool mayrounddown;
   SCIP_Bool mayroundup;
   SCIP_Bool roundup;
   SCIP_Bool lperror;
   SCIP_Longint ncalls;
   SCIP_Longint nsolsfound;
   SCIP_Longint nlpiterations;
   SCIP_Longint maxnlpiterations;
   int* roundings;
   int nvars;
   int varidx;
   int nlpcands;
   int startnlpcands;
   int depth;
   int maxdepth;
   int maxdivedepth;
   int divedepth;
   int bestcand;
   int c;

   assert(heur != NULL);
   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(scip != NULL);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DELAYED;

   /* do not call heuristic of node was already detected to be infeasible */
   if( nodeinfeasible )
      return SCIP_OKAY;

   /* only call heuristic, if an optimal LP solution is at hand */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
   if( !SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* don't dive two times at the same node */
   if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
      return SCIP_OKAY;

   *result = SCIP_DIDNOTRUN;

   /* get heuristic's data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* only apply heuristic, if only a few solutions have been found */
   if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols )
      return SCIP_OKAY;

   /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
   depth = SCIPgetDepth(scip);
   maxdepth = SCIPgetMaxDepth(scip);
   maxdepth = MAX(maxdepth, 30);
   if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
      return SCIP_OKAY;

   /* calculate the maximal number of LP iterations until heuristic is aborted */
   nlpiterations = SCIPgetNNodeLPIterations(scip);
   ncalls = SCIPheurGetNCalls(heur);
   nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
   maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
   maxnlpiterations += heurdata->maxlpiterofs;

   /* don't try to dive, if we took too many LP iterations during diving */
   if( heurdata->nlpiterations >= maxnlpiterations )
      return SCIP_OKAY;

   /* allow at least a certain number of LP iterations in this dive */
   maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);

   /* get fractional variables that should be integral */
   SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );

   /* don't try to dive, if there are no fractional variables */
   if( nlpcands == 0 )
      return SCIP_OKAY;

   /* calculate the maximal diving depth */
   nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
   if( SCIPgetNSolsFound(scip) == 0 )
      maxdivedepth = (int)(heurdata->depthfacnosol * nvars);
   else
      maxdivedepth = (int)(heurdata->depthfac * nvars);
   maxdivedepth = MIN(maxdivedepth, 10*maxdepth);


   *result = SCIP_DIDNOTFIND;

   /* get temporary memory for remembering the current soft roundings */
   SCIP_CALL( SCIPallocBufferArray(scip, &roundings, nvars) );
   BMSclearMemoryArray(roundings, nvars);

   /* start diving */
   SCIP_CALL( SCIPstartDive(scip) );

   SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing objpscostdiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d\n",
      SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth);

   /* dive as long we are in the given diving depth and iteration limits and fractional variables exist, but
    * - if the last objective change was in a direction, that corresponds to a feasible rounding, we continue in any case
    * - if possible, we dive at least with the depth 10
    * - if the number of fractional variables decreased at least with 1 variable per 2 dive depths, we continue diving
    */
   lperror = FALSE;
   lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
   divedepth = 0;
   bestcandmayrounddown = FALSE;
   bestcandmayroundup = FALSE;
   startnlpcands = nlpcands;
   while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0
      && (divedepth < 10
         || nlpcands <= startnlpcands - divedepth/2
         || (divedepth < maxdivedepth && nlpcands <= startnlpcands - divedepth/10
            && heurdata->nlpiterations < maxnlpiterations)) && !SCIPisStopped(scip) )
   {
      SCIP_RETCODE retcode;

      divedepth++;

      /* choose variable for objective change:
       * - prefer variables that may not be rounded without destroying LP feasibility:
       *   - of these variables, change objective value of variable with largest rel. difference of pseudo cost values
       * - if all remaining fractional variables may be rounded without destroying LP feasibility:
       *   - change objective value of variable with largest rel. difference of pseudo cost values
       */
      bestcand = -1;
      bestpscostquot = -1.0;
      bestcandmayrounddown = TRUE;
      bestcandmayroundup = TRUE;
      bestcandroundup = FALSE;
      for( c = 0; c < nlpcands; ++c )
      {
         var = lpcands[c];
         mayrounddown = SCIPvarMayRoundDown(var);
         mayroundup = SCIPvarMayRoundUp(var);
         primsol = lpcandssol[c];
         frac = lpcandsfrac[c];
         if( mayrounddown || mayroundup )
         {
            /* the candidate may be rounded: choose this candidate only, if the best candidate may also be rounded */
            if( bestcandmayrounddown || bestcandmayroundup )
            {
               /* choose rounding direction:
                * - if variable may be rounded in both directions, round corresponding to the pseudo cost values
                * - otherwise, round in the infeasible direction, because feasible direction is tried by rounding
                *   the current fractional solution
                */
               roundup = FALSE;
               if( mayrounddown && mayroundup )
                  calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup);
               else if( mayrounddown )
                  calcPscostQuot(scip, var, primsol, frac, +1, &pscostquot, &roundup);
               else
                  calcPscostQuot(scip, var, primsol, frac, -1, &pscostquot, &roundup);

               /* prefer variables, that have already been soft rounded but failed to get integral */
               varidx = SCIPvarGetProbindex(var);
               assert(0 <= varidx && varidx < nvars);
               if( roundings[varidx] != 0 )
                  pscostquot *= 1000.0;

               /* check, if candidate is new best candidate */
               if( pscostquot > bestpscostquot )
               {
                  bestcand = c;
                  bestpscostquot = pscostquot;
                  bestcandmayrounddown = mayrounddown;
                  bestcandmayroundup = mayroundup;
                  bestcandroundup = roundup;
               }
            }
         }
         else
         {
            /* the candidate may not be rounded: calculate pseudo cost quotient and preferred direction */
            calcPscostQuot(scip, var, primsol, frac, 0, &pscostquot, &roundup);

            /* prefer variables, that have already been soft rounded but failed to get integral */
            varidx = SCIPvarGetProbindex(var);
            assert(0 <= varidx && varidx < nvars);
            if( roundings[varidx] != 0 )
               pscostquot *= 1000.0;

            /* check, if candidate is new best candidate: prefer unroundable candidates in any case */
            if( bestcandmayrounddown || bestcandmayroundup || pscostquot > bestpscostquot )
            {
               bestcand = c;
               bestpscostquot = pscostquot;
               bestcandmayrounddown = FALSE;
               bestcandmayroundup = FALSE;
               bestcandroundup = roundup;
            }
         }
      }
      assert(bestcand != -1);

      /* if all candidates are roundable, try to round the solution */
      if( bestcandmayrounddown || bestcandmayroundup )
      {
         SCIP_Bool success;

         /* create solution from diving LP and try to round it */
         SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
         SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );

         if( success )
         {
            SCIPdebugMessage("objpscostdiving found roundable primal solution: obj=%g\n",
               SCIPgetSolOrigObj(scip, heurdata->sol));

            /* try to add solution to SCIP */
            SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

            /* check, if solution was feasible and good enough */
            if( success )
            {
               SCIPdebugMessage(" -> solution was feasible and good enough\n");
               *result = SCIP_FOUNDSOL;
            }
         }
      }

      var = lpcands[bestcand];

      /* check, if the best candidate was already subject to soft rounding */
      varidx = SCIPvarGetProbindex(var);
      assert(0 <= varidx && varidx < nvars);
      if( roundings[varidx] == +1 )
      {
         /* variable was already soft rounded upwards: hard round it downwards */
         SCIP_CALL( SCIPchgVarUbDive(scip, var, SCIPfeasFloor(scip, lpcandssol[bestcand])) );
         SCIPdebugMessage("  dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded upwards -> bounds=[%g,%g]\n",
            divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
            lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
      }
      else if( roundings[varidx] == -1 )
      {
         /* variable was already soft rounded downwards: hard round it upwards */
         SCIP_CALL( SCIPchgVarLbDive(scip, var, SCIPfeasCeil(scip, lpcandssol[bestcand])) );
         SCIPdebugMessage("  dive %d/%d: var <%s>, round=%u/%u, sol=%g, was already soft rounded downwards -> bounds=[%g,%g]\n",
            divedepth, maxdivedepth, SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
            lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var));
      }
      else
      {
         assert(roundings[varidx] == 0);

         /* apply soft rounding of best candidate via a change in the objective value */
         objscale = divedepth * 1000.0;
         oldobj = SCIPgetVarObjDive(scip, var);
         if( bestcandroundup )
         {
            /* soft round variable up: make objective value (more) negative */
            if( oldobj < 0.0 )
               newobj = objscale * oldobj;
            else
               newobj = -objscale * oldobj;
            newobj = MIN(newobj, -objscale);

            /* remember, that this variable was soft rounded upwards */
            roundings[varidx] = +1;
         }
         else
         {
            /* soft round variable down: make objective value (more) positive */
            if( oldobj > 0.0 )
               newobj = objscale * oldobj;
            else
               newobj = -objscale * oldobj;
            newobj = MAX(newobj, objscale);

            /* remember, that this variable was soft rounded downwards */
            roundings[varidx] = -1;
         }
         SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) );
         SCIPdebugMessage("  dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT": var <%s>, round=%u/%u, sol=%g, bounds=[%g,%g], obj=%g, newobj=%g\n",
            divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations,
            SCIPvarGetName(var), bestcandmayrounddown, bestcandmayroundup,
            lpcandssol[bestcand], SCIPgetVarLbDive(scip, var), SCIPgetVarUbDive(scip, var), oldobj, newobj);
      }

      /* resolve the diving LP */
      nlpiterations = SCIPgetNLPIterations(scip);
      retcode =  SCIPsolveDiveLP(scip, MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL);
      lpsolstat = SCIPgetLPSolstat(scip);

      /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
       * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
       */
      if( retcode != SCIP_OKAY )
      {
#ifndef NDEBUG
         if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
         {
            SCIP_CALL( retcode );
         }
#endif
         SCIPwarningMessage(scip, "Error while solving LP in Objpscostdiving heuristic; LP solve terminated with code <%d>\n", retcode);
         SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
      }

      if( lperror )
         break;

      /* update iteration count */
      heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;

      /* get LP solution status  and fractional variables, that should be integral */
      if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
      {
         /* get new fractional variables */
         SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, &lpcandsfrac, &nlpcands, NULL, NULL) );
      }
      SCIPdebugMessage("   -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands);
   }

   /* check if a solution has been found */
   if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
   {
      SCIP_Bool success;

      /* create solution from diving LP */
      SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
      SCIPdebugMessage("objpscostdiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));

      /* try to add solution to SCIP */
      SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

      /* check, if solution was feasible and good enough */
      if( success )
      {
         SCIPdebugMessage(" -> solution was feasible and good enough\n");
         *result = SCIP_FOUNDSOL;
      }
   }

   /* end diving */
   SCIP_CALL( SCIPendDive(scip) );

   if( *result == SCIP_FOUNDSOL )
      heurdata->nsuccess++;

   /* free temporary memory for remembering the current soft roundings */
   SCIPfreeBufferArray(scip, &roundings);

   SCIPdebugMessage("objpscostdiving heuristic finished\n");

   return SCIP_OKAY;
}
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecZirounding)
{  /*lint --e{715}*/
   SCIP_HEURDATA*     heurdata;
   SCIP_SOL*          sol;
   SCIP_VAR**         lpcands;
   SCIP_VAR**         zilpcands;

   SCIP_VAR**         slackvars;
   SCIP_Real*         upslacks;
   SCIP_Real*         downslacks;
   SCIP_Real*         activities;
   SCIP_Real*         slackvarcoeffs;
   SCIP_Bool*         rowneedsslackvar;

   SCIP_ROW**         rows;
   SCIP_Real*         lpcandssol;
   SCIP_Real*         solarray;

   SCIP_Longint       nlps;
   int                currentlpcands;
   int                nlpcands;
   int                nimplfracs;
   int                i;
   int                c;
   int                nslacks;
   int                nroundings;

   SCIP_RETCODE       retcode;

   SCIP_Bool          improvementfound;
   SCIP_Bool          numericalerror;

   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DIDNOTRUN;

   /* do not call heuristic of node was already detected to be infeasible */
   if( nodeinfeasible )
      return SCIP_OKAY;

   /* only call heuristic if an optimal LP-solution is at hand */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* get heuristic data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* Do not call heuristic if deactivation check is enabled and percentage of found solutions in relation
    * to number of calls falls below heurdata->stoppercentage */
   if( heurdata->stopziround && SCIPheurGetNCalls(heur) >= heurdata->minstopncalls
      && SCIPheurGetNSolsFound(heur)/(SCIP_Real)SCIPheurGetNCalls(heur) < heurdata->stoppercentage )
      return SCIP_OKAY;

   /* assure that heuristic has not already been called after the last LP had been solved */
   nlps = SCIPgetNLPs(scip);
   if( nlps == heurdata->lastlp )
      return SCIP_OKAY;

   heurdata->lastlp = nlps;

   /* get fractional variables */
   SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, &nimplfracs) );
   nlpcands = nlpcands + nimplfracs;
   /* make sure that there is at least one fractional variable that should be integral */
   if( nlpcands == 0 )
      return SCIP_OKAY;

   assert(nlpcands > 0);
   assert(lpcands != NULL);
   assert(lpcandssol != NULL);

   /* get LP rows data */
   rows    = SCIPgetLPRows(scip);
   nslacks = SCIPgetNLPRows(scip);

   /* cannot do anything if LP is empty */
   if( nslacks == 0 )
      return SCIP_OKAY;

   assert(rows != NULL);
   assert(nslacks > 0);

   /* get the working solution from heuristic's local data */
   sol = heurdata->sol;
   assert(sol != NULL);

   *result = SCIP_DIDNOTFIND;

   solarray = NULL;
   zilpcands = NULL;

   retcode = SCIP_OKAY;
   /* copy the current LP solution to the working solution and allocate memory for local data */
   SCIP_CALL( SCIPlinkLPSol(scip, sol) );
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &solarray, nlpcands), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &zilpcands, nlpcands), TERMINATE);

   /* copy necessary data to local arrays */
   BMScopyMemoryArray(solarray, lpcandssol, nlpcands);
   BMScopyMemoryArray(zilpcands, lpcands, nlpcands);

   /* allocate buffer data arrays */
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvars, nslacks), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &upslacks, nslacks), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &downslacks, nslacks), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &slackvarcoeffs, nslacks), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &rowneedsslackvar, nslacks), TERMINATE);
   SCIP_CALL_TERMINATE(retcode, SCIPallocBufferArray(scip, &activities, nslacks), TERMINATE);

   BMSclearMemoryArray(slackvars, nslacks);
   BMSclearMemoryArray(slackvarcoeffs, nslacks);
   BMSclearMemoryArray(rowneedsslackvar, nslacks);

   numericalerror = FALSE;
   nroundings = 0;

   /* loop over fractional variables and involved LP rows to find all rows which require a slack variable */
   for( c = 0; c < nlpcands; ++c )
   {
      SCIP_VAR* cand;
      SCIP_ROW** candrows;
      int r;
      int ncandrows;

      cand = zilpcands[c];
      assert(cand != NULL);
      assert(SCIPcolGetLPPos(SCIPvarGetCol(cand)) >= 0);

      candrows = SCIPcolGetRows(SCIPvarGetCol(cand));
      ncandrows = SCIPcolGetNLPNonz(SCIPvarGetCol(cand));

      assert(candrows == NULL || ncandrows > 0);

      for( r = 0; r < ncandrows; ++r )
      {
         int rowpos;

         assert(candrows != NULL); /* to please flexelint */
         assert(candrows[r] != NULL);
         rowpos = SCIProwGetLPPos(candrows[r]);

         if( rowpos >= 0 && SCIPisFeasEQ(scip, SCIProwGetLhs(candrows[r]), SCIProwGetRhs(candrows[r])) )
         {
            rowneedsslackvar[rowpos] = TRUE;
            SCIPdebugMessage("  Row %s needs slack variable for variable %s\n", SCIProwGetName(candrows[r]), SCIPvarGetName(cand));
         }
      }
   }

   /* calculate row slacks for every every row that belongs to the current LP and ensure, that the current solution
    * has no violated constraint -- if any constraint is violated, i.e. a slack is significantly smaller than zero,
    * this will cause the termination of the heuristic because Zirounding does not provide feasibility recovering
    */
   for( i = 0; i < nslacks; ++i )
   {
      SCIP_ROW*          row;
      SCIP_Real          lhs;
      SCIP_Real          rhs;

      row = rows[i];

      assert(row != NULL);

      lhs = SCIProwGetLhs(row);
      rhs = SCIProwGetRhs(row);

      /* get row activity */
      activities[i] = SCIPgetRowActivity(scip, row);
      assert(SCIPisFeasLE(scip, lhs, activities[i]) && SCIPisFeasLE(scip, activities[i], rhs));

      /* in special case if LHS or RHS is (-)infinity slacks have to be initialized as infinity */
      if( SCIPisInfinity(scip, -lhs) )
         downslacks[i] = SCIPinfinity(scip);
      else
         downslacks[i] = activities[i] - lhs;

      if( SCIPisInfinity(scip, rhs) )
         upslacks[i] = SCIPinfinity(scip);
      else
         upslacks[i] = rhs - activities[i];

      SCIPdebugMessage("lhs:%5.2f <= act:%5.2g <= rhs:%5.2g --> down: %5.2g, up:%5.2g\n", lhs, activities[i], rhs, downslacks[i], upslacks[i]);

      /* row is an equation. Try to find a slack variable in the row, i.e.,
       * a continuous variable which occurs only in this row. If no such variable exists,
       * there is no hope for an IP-feasible solution in this round
       */
      if( SCIPisFeasEQ(scip, lhs, rhs) && rowneedsslackvar[i] )
      {
         /* @todo: This is only necessary for rows containing fractional variables. */
         rowFindSlackVar(scip, row, &(slackvars[i]), &(slackvarcoeffs[i]));

         if( slackvars[i] == NULL )
         {
            SCIPdebugMessage("No slack variable found for equation %s, terminating ZI Round heuristic\n", SCIProwGetName(row));
            goto TERMINATE;
         }
         else
         {
            SCIP_Real ubslackvar;
            SCIP_Real lbslackvar;
            SCIP_Real solvalslackvar;
            SCIP_Real coeffslackvar;
            SCIP_Real ubgap;
            SCIP_Real lbgap;

            assert(SCIPvarGetType(slackvars[i]) == SCIP_VARTYPE_CONTINUOUS);
            solvalslackvar = SCIPgetSolVal(scip, sol, slackvars[i]);
            ubslackvar = SCIPvarGetUbGlobal(slackvars[i]);
            lbslackvar = SCIPvarGetLbGlobal(slackvars[i]);

            coeffslackvar = slackvarcoeffs[i];
            assert(!SCIPisFeasZero(scip, coeffslackvar));

            ubgap = ubslackvar - solvalslackvar;
            lbgap = solvalslackvar - lbslackvar;

            if( SCIPisFeasZero(scip, ubgap) )
              ubgap = 0.0;
            if( SCIPisFeasZero(scip, lbgap) )
              lbgap = 0.0;

            if( SCIPisFeasPositive(scip, coeffslackvar) )
            {
              if( !SCIPisInfinity(scip, lbslackvar) )
                upslacks[i] += coeffslackvar * lbgap;
              else
                upslacks[i] = SCIPinfinity(scip);
              if( !SCIPisInfinity(scip, ubslackvar) )
                downslacks[i] += coeffslackvar * ubgap;
              else
                downslacks[i] = SCIPinfinity(scip);
            }
            else
            {
               if( !SCIPisInfinity(scip, ubslackvar) )
                  upslacks[i] -= coeffslackvar * ubgap;
               else
                  upslacks[i] = SCIPinfinity(scip);
               if( !SCIPisInfinity(scip, lbslackvar) )
                  downslacks[i] -= coeffslackvar * lbgap;
               else
                  downslacks[i] = SCIPinfinity(scip);
            }
            SCIPdebugMessage("  Slack variable for row %s at pos %d: %g <= %s = %g <= %g; Coeff %g, upslack = %g, downslack = %g  \n",
               SCIProwGetName(row), SCIProwGetLPPos(row), lbslackvar, SCIPvarGetName(slackvars[i]), solvalslackvar, ubslackvar, coeffslackvar,
               upslacks[i], downslacks[i]);
         }
      }
      /* due to numerical inaccuracies, the rows might be feasible, even if the slacks are
       * significantly smaller than zero -> terminate
       */
      if( SCIPisFeasLT(scip, upslacks[i], 0.0) || SCIPisFeasLT(scip, downslacks[i], 0.0) )
         goto TERMINATE;
   }

   assert(nslacks == 0 || (upslacks != NULL && downslacks != NULL && activities != NULL));

   /* initialize number of remaining variables and flag to enter the main loop */
   currentlpcands = nlpcands;
   improvementfound = TRUE;

   /* iterate over variables as long as there are fractional variables left */
   while( currentlpcands > 0 && improvementfound && (heurdata->maxroundingloops == -1 || nroundings < heurdata->maxroundingloops) )
   {  /*lint --e{850}*/
      improvementfound = FALSE;
      nroundings++;
      SCIPdebugMessage("zirounding enters while loop for %d time with %d candidates left. \n", nroundings, currentlpcands);

      /* check for every remaining fractional variable if a shifting decreases ZI-value of the variable */
      for( c = 0; c < currentlpcands; ++c )
      {
         SCIP_VAR* var;
         SCIP_Real oldsolval;
         SCIP_Real upperbound;
         SCIP_Real lowerbound;
         SCIP_Real up;
         SCIP_Real down;
         SCIP_Real ziup;
         SCIP_Real zidown;
         SCIP_Real zicurrent;
         SCIP_Real shiftval;

         DIRECTION direction;

         /* get values from local data */
         oldsolval = solarray[c];
         var = zilpcands[c];

         assert(!SCIPisFeasIntegral(scip, oldsolval));
         assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN);

         /* calculate bounds for variable and make sure that there are no numerical inconsistencies */
         upperbound = SCIPinfinity(scip);
         lowerbound = SCIPinfinity(scip);
         calculateBounds(scip, var, oldsolval, &upperbound, &lowerbound, upslacks, downslacks, nslacks, &numericalerror);

         if( numericalerror )
            goto TERMINATE;

         /* calculate the possible values after shifting */
         up   = oldsolval + upperbound;
         down = oldsolval - lowerbound;

         /* if the variable is integer or implicit binary, do not shift further than the nearest integer */
         if( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY)
         {
            SCIP_Real ceilx;
            SCIP_Real floorx;

            ceilx = SCIPfeasCeil(scip, oldsolval);
            floorx = SCIPfeasFloor(scip, oldsolval);
            up   = MIN(up, ceilx);
            down = MAX(down, floorx);
         }

         /* calculate necessary values */
         ziup      = getZiValue(scip, up);
         zidown    = getZiValue(scip, down);
         zicurrent = getZiValue(scip, oldsolval);

         /* calculate the shifting direction that reduces ZI-value the most,
          * if both directions improve ZI-value equally, take the direction which improves the objective
          */
         if( SCIPisFeasLT(scip, zidown, zicurrent) || SCIPisFeasLT(scip, ziup, zicurrent) )
         {
            if( SCIPisFeasEQ(scip,ziup, zidown) )
               direction  = SCIPisFeasGE(scip, SCIPvarGetObj(var), 0.0) ? DIRECTION_DOWN : DIRECTION_UP;
            else if( SCIPisFeasLT(scip, zidown, ziup) )
               direction = DIRECTION_DOWN;
            else
               direction = DIRECTION_UP;

            /* once a possible shifting direction and value have been found, variable value is updated */
            shiftval = (direction == DIRECTION_UP ? up - oldsolval : down - oldsolval);

            /* this improves numerical stability in some cases */
            if( direction == DIRECTION_UP )
               shiftval = MIN(shiftval, upperbound);
            else
               shiftval = MIN(shiftval, lowerbound);
            /* update the solution */
            solarray[c] = direction == DIRECTION_UP ? up : down;
            SCIP_CALL( SCIPsetSolVal(scip, sol, var, solarray[c]) );

            /* update the rows activities and slacks */
            SCIP_CALL( updateSlacks(scip, sol, var, shiftval, upslacks,
                  downslacks, activities, slackvars, slackvarcoeffs, nslacks) );

            SCIPdebugMessage("zirounding update step : %d var index, oldsolval=%g, shiftval=%g\n",
               SCIPvarGetIndex(var), oldsolval, shiftval);
            /* since at least one improvement has been found, heuristic will enter main loop for another time because the improvement
             * might affect many LP rows and their current slacks and thus make further rounding steps possible */
            improvementfound = TRUE;
         }

         /* if solution value of variable has become feasibly integral due to rounding step,
          * variable is put at the end of remaining candidates array so as not to be considered in future loops
          */
         if( SCIPisFeasIntegral(scip, solarray[c]) )
         {
            zilpcands[c] = zilpcands[currentlpcands - 1];
            solarray[c] = solarray[currentlpcands - 1];
            currentlpcands--;

            /* counter is decreased if end of candidates array has not been reached yet */
            if( c < currentlpcands )
               c--;
         }
         else if( nroundings == heurdata->maxroundingloops - 1 )
            goto TERMINATE;
      }
   }

   /* in case that no candidate is left for rounding after the final main loop
    * the found solution has to be checked for feasibility in the original problem
    */
   if( currentlpcands == 0 )
   {
      SCIP_Bool stored;
      SCIP_CALL(SCIPtrySol(scip, sol, FALSE, FALSE, TRUE, FALSE, &stored));
      if( stored )
      {
#ifdef SCIP_DEBUG
         SCIPdebugMessage("found feasible rounded solution:\n");
         SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) );
#endif
         SCIPstatisticMessage("  ZI Round solution value: %g \n", SCIPgetSolOrigObj(scip, sol));

         *result = SCIP_FOUNDSOL;
      }
   }

   /* free memory for all locally allocated data */
 TERMINATE:
   SCIPfreeBufferArrayNull(scip, &activities);
   SCIPfreeBufferArrayNull(scip, &rowneedsslackvar);
   SCIPfreeBufferArrayNull(scip, &slackvarcoeffs);
   SCIPfreeBufferArrayNull(scip, &downslacks);
   SCIPfreeBufferArrayNull(scip, &upslacks);
   SCIPfreeBufferArrayNull(scip, &slackvars);
   SCIPfreeBufferArrayNull(scip, &zilpcands);
   SCIPfreeBufferArrayNull(scip, &solarray);

   return retcode;
}
/** find fitting binary variable aggregation for downlock case */
static
void getBinVarIdxInDownlockRow(
   SCIP*                 scip,               /**< SCIP main data structure */
   SCIPMILPMATRIX*       matrix,             /**< constraint matrix */
   int                   aggvaridx,          /**< index of variable which should be aggregated */
   int*                  binvaridx,          /**< pointer to store index of binary variable */
   AGGRTYPE*             aggtype             /**< pointer to store type of aggregation */
   )
{
   int rowidx;
   SCIP_Real coef;
   int* rowpnt;
   int* rowend;
   SCIP_Real* valpnt;
   SCIP_Real minact;
   SCIP_Real maxact;
   SCIP_Real lhs;
   SCIP_Real ub;

   assert(binvaridx != NULL);
   assert(aggtype != NULL);

   *binvaridx = -1;
   *aggtype = NOAGG;

   getDownlockRowIdx(matrix, aggvaridx, &rowidx, &coef);

   if( rowidx < 0 )
      return;

   assert(coef > 0);
   minact = SCIPmatrixGetRowMinActivity(matrix, rowidx);
   maxact = SCIPmatrixGetRowMaxActivity(matrix, rowidx);

   if( SCIPisInfinity(scip, -minact) || SCIPisInfinity(scip, maxact) )
      return;

   lhs = SCIPmatrixGetRowLhs(matrix, rowidx);
   ub = SCIPmatrixGetColUb(matrix, aggvaridx);

   /* search for appropriate binary variables */
   rowpnt = SCIPmatrixGetRowIdxPtr(matrix, rowidx);
   rowend = rowpnt + SCIPmatrixGetRowNNonzs(matrix, rowidx);
   valpnt = SCIPmatrixGetRowValPtr(matrix, rowidx);
   for( ; (rowpnt < rowend); rowpnt++, valpnt++ )
   {
      SCIP_VAR* var;

      if( *rowpnt == aggvaridx )
         continue;

      var = SCIPmatrixGetVar(matrix, *rowpnt);

      /* avoid cases where the binary variable has lb=ub=1 or lb=ub=0 */
      if( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY &&
          SCIPmatrixGetColLb(matrix, *rowpnt) < 0.5 &&
          SCIPmatrixGetColUb(matrix, *rowpnt) > 0.5 )
      {
         SCIP_Real bincoef;

         bincoef = *valpnt;

         if( bincoef < 0 )
         {
            /* binvar = 0 implies that the constraint is redundant */
            if( SCIPisGE(scip, minact-bincoef, lhs) )
            {
               /* binvar = 1 implies that aggvar = ub */
               SCIP_Real bnd;
               bnd = (lhs - maxact + coef*ub - bincoef) / coef;
               if( SCIPisGE(scip, bnd, ub) )
               {
                  *binvaridx = *rowpnt;
                  *aggtype = BIN0LBOUND;
                  break;
               }
            }
         }

         if( bincoef > 0 )
         {
            /* binvar = 1 implies that the constraint is redundant */
            if( SCIPisGE(scip, minact+bincoef, lhs) )
            {
               /* binvar = 0 implies that aggvar = ub */
               SCIP_Real bnd;
               bnd = (lhs - maxact + coef*ub + bincoef) / coef;
               if( SCIPisGE(scip, bnd, ub) )
               {
                  *binvaridx = *rowpnt;
                  *aggtype = BIN0UBOUND;
                  break;
               }
            }
         }
      }
   }
}
Exemple #10
0
/**
 * Selects a variable from a set of candidates by strong branching
 *
 *  @return \ref SCIP_OKAY is returned if everything worked. Otherwise a suitable error code is passed. See \ref
 *          SCIP_Retcode "SCIP_RETCODE" for a complete list of error codes.
 *
 * @note The variables in the lpcands array must have a fractional value in the current LP solution
 */
SCIP_RETCODE SCIPselectVarPseudoStrongBranching(
   SCIP*                 scip,               /**< original SCIP data structure                        */
   SCIP_VAR**            pseudocands,        /**< branching candidates                                */
   SCIP_Bool*            skipdown,           /**< should down branchings be skipped? */
   SCIP_Bool*            skipup,             /**< should up branchings be skipped? */
   int                   npseudocands,       /**< number of branching candidates                      */
   int                   npriopseudocands,   /**< number of priority branching candidates             */
   SCIP_Bool             allowaddcons,       /**< is the branching rule allowed to add constraints?   */
   int*                  bestpseudocand,     /**< best candidate for branching                        */
   SCIP_Real*            bestdown,           /**< objective value of the down branch for bestcand     */
   SCIP_Real*            bestup,             /**< objective value of the up branch for bestcand       */
   SCIP_Real*            bestscore,          /**< score for bestcand                                  */
   SCIP_Bool*            bestdownvalid,      /**< is bestdown a valid dual bound for the down branch? */
   SCIP_Bool*            bestupvalid,        /**< is bestup a valid dual bound for the up branch?     */
   SCIP_Real*            provedbound,        /**< proved dual bound for current subtree               */
   SCIP_RESULT*          result              /**< result pointer                                      */
   )
{
   SCIP_Real lpobjval;
   SCIP_Bool allcolsinlp;
   SCIP_Bool exactsolve;
#ifndef NDEBUG
   SCIP_Real cutoffbound;
   cutoffbound = SCIPgetCutoffbound(scip);
#endif


   assert(scip != NULL);
   assert(pseudocands != NULL);
   assert(bestpseudocand != NULL);
   assert(skipdown != NULL);
   assert(skipup != NULL);
   assert(bestdown != NULL);
   assert(bestup != NULL);
   assert(bestscore != NULL);
   assert(bestdownvalid != NULL);
   assert(bestupvalid != NULL);
   assert(provedbound != NULL);
   assert(result != NULL);
   assert(SCIPgetLPSolstat(scip) == SCIP_LPSOLSTAT_OPTIMAL);

   /* get current LP objective bound of the local sub problem and global cutoff bound */
   lpobjval = SCIPgetLPObjval(scip);

   /* check, if we want to solve the problem exactly, meaning that strong branching information is not useful
    * for cutting off sub problems and improving lower bounds of children
    */
   exactsolve = SCIPisExactSolve(scip);

   /* check, if all existing columns are in LP, and thus the strong branching results give lower bounds */
   allcolsinlp = SCIPallColsInLP(scip);

   /* if only one candidate exists, choose this one without applying strong branching */
   *bestpseudocand = 0;
   *bestdown = lpobjval;
   *bestup = lpobjval;
   *bestdownvalid = TRUE;
   *bestupvalid = TRUE;
   *bestscore = -SCIPinfinity(scip);
   *provedbound = lpobjval;
   if( npseudocands > 1 )
   {
      SCIP_BRANCHRULE* branchrule;
      SCIP_BRANCHRULEDATA* branchruledata;

      SCIP_Real solval;
      SCIP_Real down;
      SCIP_Real up;
      SCIP_Real downgain;
      SCIP_Real upgain;
      SCIP_Real score;
      SCIP_Bool integral;
      SCIP_Bool lperror;
      SCIP_Bool downvalid;
      SCIP_Bool upvalid;
      SCIP_Bool downinf;
      SCIP_Bool upinf;
      SCIP_Bool downconflict;
      SCIP_Bool upconflict;
      int nsbcalls;
      int i;
      int c;

      branchrule = SCIPfindBranchrule(scip, BRANCHRULE_NAME);
      assert(branchrule != NULL);

      /* get branching rule data */
      branchruledata = SCIPbranchruleGetData(branchrule);
      assert(branchruledata != NULL);


      /* initialize strong branching */
      SCIP_CALL( SCIPstartStrongbranch(scip, FALSE) );

      /* search the full strong candidate:
       * cycle through the candidates, starting with the position evaluated in the last run
       */
      nsbcalls = 0;
      for( i = 0, c = branchruledata->lastcand; i < npseudocands; ++i, ++c )
      {
         c = c % npseudocands;
         assert(pseudocands[c] != NULL);

         /* we can only apply strong branching on COLUMN variables that are in the current LP */
         if( !SCIPvarIsInLP(pseudocands[c]) )
            continue;

         solval = SCIPvarGetLPSol(pseudocands[c]);
         integral = SCIPisFeasIntegral(scip, solval);

         SCIPdebugMessage("applying strong branching on %s variable <%s>[%g,%g] with solution %g\n",
            integral ? "integral" : "fractional", SCIPvarGetName(pseudocands[c]), SCIPvarGetLbLocal(pseudocands[c]),
            SCIPvarGetUbLocal(pseudocands[c]), solval);

         up = -SCIPinfinity(scip);
         down = -SCIPinfinity(scip);

         if( integral )
         {
            SCIP_CALL( SCIPgetVarStrongbranchInt(scip, pseudocands[c], INT_MAX,
                  skipdown[c] ? NULL : &down, skipup[c] ? NULL : &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror) );
         }
         else
         {
            SCIP_CALL( SCIPgetVarStrongbranchFrac(scip, pseudocands[c], INT_MAX,
                  skipdown[c] ? NULL : &down, skipup[c] ? NULL : &up, &downvalid, &upvalid, &downinf, &upinf, &downconflict, &upconflict, &lperror) );
         }
         nsbcalls++;

         /* display node information line in root node */
         if( SCIPgetDepth(scip) == 0 && nsbcalls % 100 == 0 )
         {
            SCIP_CALL( SCIPprintDisplayLine(scip, NULL, SCIP_VERBLEVEL_HIGH, TRUE) );
         }

         /* check for an error in strong branching */
         if( lperror )
         {
            SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL,
               "(node %"SCIP_LONGINT_FORMAT") error in strong branching call for variable <%s> with solution %g\n",
               SCIPgetNNodes(scip), SCIPvarGetName(pseudocands[c]), solval);
            break;
         }

         /* evaluate strong branching */
         down = MAX(down, lpobjval);
         up = MAX(up, lpobjval);
         downgain = down - lpobjval;
         upgain = up - lpobjval;
         assert(!allcolsinlp || exactsolve || !downvalid || downinf == SCIPisGE(scip, down, cutoffbound));
         assert(!allcolsinlp || exactsolve || !upvalid || upinf == SCIPisGE(scip, up, cutoffbound));
         assert(downinf || !downconflict);
         assert(upinf || !upconflict);

         /* check if there are infeasible roundings */
         if( downinf || upinf )
         {
            assert(allcolsinlp);
            assert(!exactsolve);

            /* if for both infeasibilities, a conflict constraint was created, we don't need to fix the variable by hand,
             * but better wait for the next propagation round to fix them as an inference, and potentially produce a
             * cutoff that can be analyzed
             */
            if( allowaddcons && downinf == downconflict && upinf == upconflict )
            {
               *result = SCIP_CONSADDED;
               break; /* terminate initialization loop, because constraint was added */
            }
            else if( downinf && upinf )
            {
               if( integral )
               {
                  SCIP_Bool infeasible;
                  SCIP_Bool fixed;

                  /* both bound changes are infeasible: variable can be fixed to its current value */
                  SCIP_CALL( SCIPfixVar(scip, pseudocands[c], solval, &infeasible, &fixed) );
                  assert(!infeasible);
                  assert(fixed);
                  *result = SCIP_REDUCEDDOM;
                  SCIPdebugMessage(" -> integral variable <%s> is infeasible in both directions\n",
                     SCIPvarGetName(pseudocands[c]));
                  break; /* terminate initialization loop, because LP was changed */
               }
               else
               {
                  /* both roundings are infeasible: the node is infeasible */
                  *result = SCIP_CUTOFF;
                  SCIPdebugMessage(" -> fractional variable <%s> is infeasible in both directions\n",
                     SCIPvarGetName(pseudocands[c]));
                  break; /* terminate initialization loop, because node is infeasible */
               }
            }
            else if( downinf )
            {
               SCIP_Real newlb;

               /* downwards rounding is infeasible -> change lower bound of variable to upward rounding */
               newlb = SCIPfeasCeil(scip, solval);
               if( SCIPvarGetLbLocal(pseudocands[c]) < newlb - 0.5 )
               {
                  SCIP_CALL( SCIPchgVarLb(scip, pseudocands[c], newlb) );
                  *result = SCIP_REDUCEDDOM;
                  SCIPdebugMessage(" -> variable <%s> is infeasible in downward branch\n", SCIPvarGetName(pseudocands[c]));
                  break; /* terminate initialization loop, because LP was changed */
               }
            }
            else
            {
               SCIP_Real newub;

               /* upwards rounding is infeasible -> change upper bound of variable to downward rounding */
               assert(upinf);
               newub = SCIPfeasFloor(scip, solval);
               if( SCIPvarGetUbLocal(pseudocands[c]) > newub + 0.5 )
               {
                  SCIP_CALL( SCIPchgVarUb(scip, pseudocands[c], newub) );
                  *result = SCIP_REDUCEDDOM;
                  SCIPdebugMessage(" -> variable <%s> is infeasible in upward branch\n", SCIPvarGetName(pseudocands[c]));
                  break; /* terminate initialization loop, because LP was changed */
               }
            }
         }
         else if( allcolsinlp && !exactsolve && downvalid && upvalid )
         {
            SCIP_Real minbound;

            /* the minimal lower bound of both children is a proved lower bound of the current subtree */
            minbound = MIN(down, up);
            *provedbound = MAX(*provedbound, minbound);
         }

         /* check for a better score, if we are within the maximum priority candidates */
         if( c < npriopseudocands )
         {
            if( integral )
            {

               if( skipdown[c] )
               {
                  downgain = 0.0;
                  score = SCIPgetBranchScore(scip, pseudocands[c], downgain, upgain);
               }
               else if( skipup[c] )
               {
                  upgain = 0.0;
                  score = SCIPgetBranchScore(scip, pseudocands[c], downgain, upgain);
               }
               else
               {
                  SCIP_Real gains[3];

                  gains[0] = downgain;
                  gains[1] = 0.0;
                  gains[2] = upgain;
                  score = SCIPgetBranchScoreMultiple(scip, pseudocands[c], 3, gains);
               }
            }
            else
               score = SCIPgetBranchScore(scip, pseudocands[c], downgain, upgain);

            if( score > *bestscore )
            {
               *bestpseudocand = c;
               *bestdown = down;
               *bestup = up;
               *bestdownvalid = downvalid;
               *bestupvalid = upvalid;
               *bestscore = score;
            }
         }
         else
            score = 0.0;

         /* update pseudo cost values */
         if( !downinf )
         {
            SCIP_CALL( SCIPupdateVarPseudocost(scip, pseudocands[c],
                  solval-SCIPfeasCeil(scip, solval-1.0), downgain, 1.0) );
         }
         if( !upinf )
         {
            SCIP_CALL( SCIPupdateVarPseudocost(scip, pseudocands[c],
                  solval-SCIPfeasFloor(scip, solval+1.0), upgain, 1.0) );
         }

         SCIPdebugMessage(" -> var <%s> (solval=%g, downgain=%g, upgain=%g, score=%g) -- best: <%s> (%g)\n",
            SCIPvarGetName(pseudocands[c]), solval, downgain, upgain, score,
            SCIPvarGetName(pseudocands[*bestpseudocand]), *bestscore);
      }

      /* remember last evaluated candidate */
      branchruledata->lastcand = c;

      /* end strong branching */
      SCIP_CALL( SCIPendStrongbranch(scip) );
   }

   return SCIP_OKAY;
}
Exemple #11
0
/** searches and adds implied bound cuts that are violated by the given solution value array */
static
SCIP_RETCODE separateCuts(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_SEPA*            sepa,               /**< separator */
   SCIP_SOL*             sol,                /**< the solution that should be separated, or NULL for LP solution */
   SCIP_Real*            solvals,            /**< array with solution values of all problem variables */
   SCIP_VAR**            fracvars,           /**< array of fractional variables */
   SCIP_Real*            fracvals,           /**< solution values of fractional variables */
   int                   nfracs,             /**< number of fractional variables */
   SCIP_Bool*            cutoff,             /**< whether a cutoff has been detected */
   int*                  ncuts               /**< pointer to store the number of generated cuts */
   )
{
   SCIP_CLIQUE** cliques;
   SCIP_SEPADATA* sepadata;
   int ncliques;
   int i;

   assert(solvals != NULL);
   assert(fracvars != NULL || nfracs == 0);
   assert(fracvals != NULL || nfracs == 0);
   assert(cutoff != NULL);
   assert(ncuts != NULL);

   *cutoff = FALSE;
   *ncuts = 0;
   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   SCIPdebugMessage("searching for implied bound cuts\n");

   /* search binary variables for violated implications */
   for( i = 0; i < nfracs; i++ )
   {
      SCIP_BOUNDTYPE* impltypes; 
      SCIP_Real* implbounds; 
      SCIP_VAR** implvars;
      int nimpl;
      int j;

      assert(fracvars != NULL);
      assert(fracvals != NULL);

      /* only process binary variables */
      if( SCIPvarGetType(fracvars[i]) != SCIP_VARTYPE_BINARY )
         continue;

      /* get implications of x == 1 */
      nimpl = SCIPvarGetNImpls(fracvars[i], TRUE);
      implvars = SCIPvarGetImplVars(fracvars[i], TRUE);
      impltypes = SCIPvarGetImplTypes(fracvars[i], TRUE);
      implbounds = SCIPvarGetImplBounds(fracvars[i], TRUE);

      /*debugMessage("%d implications for <%s>[%g] == 1\n", nimpl, SCIPvarGetName(fracvars[i]), fracvals[i]);*/

      /* try to add cuts for implications of x == 1
       *    x == 1 -> y <= p:  y <= ub + x * (p - ub)  <==>  y + (ub - p) * x <=  ub
       *    x == 1 -> y >= p:  y >= lb + x * (p - lb)  <==> -y + (p - lb) * x <= -lb
       * with lb (ub) global lower (upper) bound of y
       */
      for( j = 0; j < nimpl; j++ )
      {
         SCIP_Real solval;

         assert(implvars != NULL);
         assert(impltypes != NULL);
         assert(implbounds != NULL);

         /* consider only implications with active implvar */
         if( SCIPvarGetProbindex(implvars[j]) < 0 )
            continue;

         solval = solvals[SCIPvarGetProbindex(implvars[j])];
         if( impltypes[j] == SCIP_BOUNDTYPE_UPPER )
         {
            SCIP_Real ub;

            /* implication x == 1 -> y <= p */
            ub = SCIPvarGetUbGlobal(implvars[j]);

            /* consider only nonredundant and numerical harmless implications */
            if( SCIPisLE(scip, implbounds[j], ub) && (ub - implbounds[j]) * SCIPfeastol(scip) <= RELCUTCOEFMAXRANGE )
            {
               /* add cut if violated */
               SCIP_CALL( addCut(scip, sepa, sol, 1.0, implvars[j], solval, (ub - implbounds[j]), fracvars[i], fracvals[i],
                     ub, cutoff, ncuts) );
               if ( *cutoff )
                  return SCIP_OKAY;
            }
         }
         else
         {
            SCIP_Real lb;

            /* implication x == 1 -> y >= p */
            lb = SCIPvarGetLbGlobal(implvars[j]);
            assert(impltypes[j] == SCIP_BOUNDTYPE_LOWER);

            /* consider only nonredundant and numerical harmless implications */
            if( SCIPisGE(scip, implbounds[j], lb) && (implbounds[j] - lb) * SCIPfeastol(scip) <= RELCUTCOEFMAXRANGE )
            {
               /* add cut if violated */
               SCIP_CALL( addCut(scip, sepa, sol, -1.0, implvars[j], solval, (implbounds[j] - lb), fracvars[i], fracvals[i],
                     -lb, cutoff, ncuts) );
               if ( *cutoff )
                  return SCIP_OKAY;
            }
         }
      }

      /* get implications of x == 0 */
      nimpl = SCIPvarGetNImpls(fracvars[i], FALSE);
      implvars = SCIPvarGetImplVars(fracvars[i], FALSE);
      impltypes = SCIPvarGetImplTypes(fracvars[i], FALSE);
      implbounds = SCIPvarGetImplBounds(fracvars[i], FALSE);

      /*debugMessage("%d implications for <%s>[%g] == 0\n", nimpl, SCIPvarGetName(fracvars[i]), fracvals[i]);*/

      /* try to add cuts for implications of x == 0
       *    x == 0 -> y <= p:  y <= p + x * (ub - p)  <==>  y + (p - ub) * x <=  p
       *    x == 0 -> y >= p:  y >= p + x * (lb - p)  <==> -y + (lb - p) * x <= -p
       * with lb (ub) global lower (upper) bound of y
       */
      for( j = 0; j < nimpl; j++ )
      {
         SCIP_Real solval;

         /* consider only implications with active implvar */
         if( SCIPvarGetProbindex(implvars[j]) < 0 )
            continue;

         solval = solvals[SCIPvarGetProbindex(implvars[j])];
         if( impltypes[j] == SCIP_BOUNDTYPE_UPPER )
         {
            SCIP_Real ub;

            /* implication x == 0 -> y <= p */
            ub = SCIPvarGetUbGlobal(implvars[j]);

            /* consider only nonredundant and numerical harmless implications */
            if( SCIPisLE(scip, implbounds[j], ub) && (ub - implbounds[j]) * SCIPfeastol(scip) < RELCUTCOEFMAXRANGE )
            {
               /* add cut if violated */
               SCIP_CALL( addCut(scip, sepa, sol, 1.0, implvars[j], solval, (implbounds[j] - ub), fracvars[i], fracvals[i],
                     implbounds[j], cutoff, ncuts) );
               if ( *cutoff )
                  return SCIP_OKAY;
            }
         }
         else
         {
            SCIP_Real lb;

            /* implication x == 0 -> y >= p */
            lb = SCIPvarGetLbGlobal(implvars[j]);
            assert(impltypes[j] == SCIP_BOUNDTYPE_LOWER);

            /* consider only nonredundant and numerical harmless implications */
            if( SCIPisGE(scip, implbounds[j], lb) && (implbounds[j] - lb) * SCIPfeastol(scip) < RELCUTCOEFMAXRANGE )
            {
               /* add cut if violated */
               SCIP_CALL( addCut(scip, sepa, sol, -1.0, implvars[j], solval, (lb - implbounds[j]), fracvars[i], fracvals[i],
                     -implbounds[j], cutoff, ncuts) );
               if ( *cutoff )
                  return SCIP_OKAY;
            }
         }
      }
   }

   /* stop separation here if cliques should not be separated */
   if( ! sepadata->usetwosizecliques )
      return SCIP_OKAY;

   /* prepare clean clique data */
   SCIP_CALL( SCIPcleanupCliques(scip, cutoff) );

   if( *cutoff )
      return SCIP_OKAY;

   cliques = SCIPgetCliques(scip);
   ncliques = SCIPgetNCliques(scip);

   /* loop over cliques of size 2 which are essentially implications and add cuts if they are violated */
   for( i = 0; i < ncliques; ++i )
   {
      SCIP_CLIQUE* clique;
      SCIP_VAR** clqvars;
      SCIP_Bool* clqvals;
      SCIP_Real rhs;

      clique = cliques[i];
      /* only consider inequality cliques of size 2 */
      if( SCIPcliqueGetNVars(clique) != 2 || SCIPcliqueIsEquation(clique) )
         continue;

      /* get variables and values of the clique */
      clqvars = SCIPcliqueGetVars(clique);
      clqvals = SCIPcliqueGetValues(clique);

      /* clique variables should never be equal after clean up */
      assert(clqvars[0] != clqvars[1]);

      /* calculate right hand side of clique inequality, which is initially 1 and decreased by 1 for every occurence of
       * a negated variable in the clique
       */
      rhs = 1.0;
      if( ! clqvals[0] )
         rhs -= 1.0;
      if( ! clqvals[1] )
         rhs -= 1.0;

      /* Basic clique inequality is
       *
       *       cx * x + (1-cx) (1-x) + cy * y + (1-cy) * (1-y) <= 1,
       *
       * where x and y are the two binary variables in the clique and cx and cy are their clique values, where a
       * clique value of 0 means that the negation of the variable should be part of the inequality.
       * Hence, exactly one of the two possible terms for x and y has a nonzero coefficient
       */
      SCIP_CALL( addCut(scip, sepa, sol,
            clqvals[0] ? 1.0 : -1.0, clqvars[0], SCIPgetSolVal(scip, sol, clqvars[0]),
            clqvals[1] ? 1.0 : -1.0, clqvars[1], SCIPgetSolVal(scip, sol, clqvars[1]),
            rhs, cutoff, ncuts) );

      /* terminate if cutoff was found */
      if( *cutoff )
         return SCIP_OKAY;
   }

   return SCIP_OKAY;
}
Exemple #12
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecShifting) /*lint --e{715}*/
{   /*lint --e{715}*/
    SCIP_HEURDATA* heurdata;
    SCIP_SOL* sol;
    SCIP_VAR** lpcands;
    SCIP_Real* lpcandssol;
    SCIP_ROW** lprows;
    SCIP_Real* activities;
    SCIP_ROW** violrows;
    SCIP_Real* nincreases;
    SCIP_Real* ndecreases;
    int* violrowpos;
    int* nfracsinrow;
    SCIP_Real increaseweight;
    SCIP_Real obj;
    SCIP_Real bestshiftval;
    SCIP_Real minobj;
    int nlpcands;
    int nlprows;
    int nvars;
    int nfrac;
    int nviolrows;
    int nprevviolrows;
    int minnviolrows;
    int nnonimprovingshifts;
    int c;
    int r;
    SCIP_Longint nlps;
    SCIP_Longint ncalls;
    SCIP_Longint nsolsfound;
    SCIP_Longint nnodes;

    assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
    assert(scip != NULL);
    assert(result != NULL);
    assert(SCIPhasCurrentNodeLP(scip));

    *result = SCIP_DIDNOTRUN;

    /* only call heuristic, if an optimal LP solution is at hand */
    if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
        return SCIP_OKAY;

    /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
    if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
        return SCIP_OKAY;

    /* get heuristic data */
    heurdata = SCIPheurGetData(heur);
    assert(heurdata != NULL);

    /* don't call heuristic, if we have already processed the current LP solution */
    nlps = SCIPgetNLPs(scip);
    if( nlps == heurdata->lastlp )
        return SCIP_OKAY;
    heurdata->lastlp = nlps;

    /* don't call heuristic, if it was not successful enough in the past */
    ncalls = SCIPheurGetNCalls(heur);
    nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
    nnodes = SCIPgetNNodes(scip);
    if( nnodes % ((ncalls/100)/(nsolsfound+1)+1) != 0 )
        return SCIP_OKAY;

    /* get fractional variables, that should be integral */
    /* todo check if heuristic should include implicit integer variables for its calculations */
    SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
    nfrac = nlpcands;

    /* only call heuristic, if LP solution is fractional */
    if( nfrac == 0 )
        return SCIP_OKAY;

    *result = SCIP_DIDNOTFIND;

    /* get LP rows */
    SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );

    SCIPdebugMessage("executing shifting heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac);

    /* get memory for activities, violated rows, and row violation positions */
    nvars = SCIPgetNVars(scip);
    SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
    SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
    SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );
    SCIP_CALL( SCIPallocBufferArray(scip, &nfracsinrow, nlprows) );
    SCIP_CALL( SCIPallocBufferArray(scip, &nincreases, nvars) );
    SCIP_CALL( SCIPallocBufferArray(scip, &ndecreases, nvars) );
    BMSclearMemoryArray(nfracsinrow, nlprows);
    BMSclearMemoryArray(nincreases, nvars);
    BMSclearMemoryArray(ndecreases, nvars);

    /* get the activities for all globally valid rows;
     * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
     */
    nviolrows = 0;
    for( r = 0; r < nlprows; ++r )
    {
        SCIP_ROW* row;

        row = lprows[r];
        assert(SCIProwGetLPPos(row) == r);

        if( !SCIProwIsLocal(row) )
        {
            activities[r] = SCIPgetRowActivity(scip, row);
            if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
                    || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
            {
                violrows[nviolrows] = row;
                violrowpos[r] = nviolrows;
                nviolrows++;
            }
            else
                violrowpos[r] = -1;
        }
    }

    /* calc the current number of fractional variables in rows */
    for( c = 0; c < nlpcands; ++c )
        addFracCounter(nfracsinrow, nlprows, lpcands[c], +1);

    /* get the working solution from heuristic's local data */
    sol = heurdata->sol;
    assert(sol != NULL);

    /* copy the current LP solution to the working solution */
    SCIP_CALL( SCIPlinkLPSol(scip, sol) );

    /* calculate the minimal objective value possible after rounding fractional variables */
    minobj = SCIPgetSolTransObj(scip, sol);
    assert(minobj < SCIPgetCutoffbound(scip));
    for( c = 0; c < nlpcands; ++c )
    {
        obj = SCIPvarGetObj(lpcands[c]);
        bestshiftval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
        minobj += obj * (bestshiftval - lpcandssol[c]);
    }

    /* try to shift remaining variables in order to become/stay feasible */
    nnonimprovingshifts = 0;
    minnviolrows = INT_MAX;
    increaseweight = 1.0;
    while( (nfrac > 0 || nviolrows > 0) && nnonimprovingshifts < MAXSHIFTINGS )
    {
        SCIP_VAR* shiftvar;
        SCIP_Real oldsolval;
        SCIP_Real newsolval;
        SCIP_Bool oldsolvalisfrac;
        int probindex;

        SCIPdebugMessage("shifting heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g), cutoff=%g\n",
                         nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj),
                         SCIPretransformObj(scip, SCIPgetCutoffbound(scip)));

        nprevviolrows = nviolrows;

        /* choose next variable to process:
         *  - if a violated row exists, shift a variable decreasing the violation, that has least impact on other rows
         *  - otherwise, shift a variable, that has strongest devastating impact on rows in opposite direction
         */
        shiftvar = NULL;
        oldsolval = 0.0;
        newsolval = 0.0;
        if( nviolrows > 0 && (nfrac == 0 || nnonimprovingshifts < MAXSHIFTINGS-1) )
        {
            SCIP_ROW* row;
            int rowidx;
            int rowpos;
            int direction;

            rowidx = -1;
            rowpos = -1;
            row = NULL;
            if( nfrac > 0 )
            {
                for( rowidx = nviolrows-1; rowidx >= 0; --rowidx )
                {
                    row = violrows[rowidx];
                    rowpos = SCIProwGetLPPos(row);
                    assert(violrowpos[rowpos] == rowidx);
                    if( nfracsinrow[rowpos] > 0 )
                        break;
                }
            }
            if( rowidx == -1 )
            {
                rowidx = SCIPgetRandomInt(0, nviolrows-1, &heurdata->randseed);
                row = violrows[rowidx];
                rowpos = SCIProwGetLPPos(row);
                assert(0 <= rowpos && rowpos < nlprows);
                assert(violrowpos[rowpos] == rowidx);
                assert(nfracsinrow[rowpos] == 0);
            }
            assert(violrowpos[rowpos] == rowidx);

            SCIPdebugMessage("shifting heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
                             SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
            SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );

            /* get direction in which activity must be shifted */
            assert(SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row))
                   || SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
            direction = SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) ? +1 : -1;

            /* search a variable that can shift the activity in the necessary direction */
            SCIP_CALL( selectShifting(scip, sol, row, activities[rowpos], direction,
                                      nincreases, ndecreases, increaseweight, &shiftvar, &oldsolval, &newsolval) );
        }

        if( shiftvar == NULL && nfrac > 0 )
        {
            SCIPdebugMessage("shifting heuristic: search rounding variable and try to stay feasible\n");
            SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &shiftvar, &oldsolval, &newsolval) );
        }

        /* check, whether shifting was possible */
        if( shiftvar == NULL || SCIPisEQ(scip, oldsolval, newsolval) )
        {
            SCIPdebugMessage("shifting heuristic:  -> didn't find a shifting variable\n");
            break;
        }

        SCIPdebugMessage("shifting heuristic:  -> shift var <%s>[%g,%g], type=%d, oldval=%g, newval=%g, obj=%g\n",
                         SCIPvarGetName(shiftvar), SCIPvarGetLbGlobal(shiftvar), SCIPvarGetUbGlobal(shiftvar), SCIPvarGetType(shiftvar),
                         oldsolval, newsolval, SCIPvarGetObj(shiftvar));

        /* update row activities of globally valid rows */
        SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows,
                                    shiftvar, oldsolval, newsolval) );
        if( nviolrows >= nprevviolrows )
            nnonimprovingshifts++;
        else if( nviolrows < minnviolrows )
        {
            minnviolrows = nviolrows;
            nnonimprovingshifts = 0;
        }

        /* store new solution value and decrease fractionality counter */
        SCIP_CALL( SCIPsetSolVal(scip, sol, shiftvar, newsolval) );

        /* update fractionality counter and minimal objective value possible after shifting remaining variables */
        oldsolvalisfrac = !SCIPisFeasIntegral(scip, oldsolval)
                          && (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER);
        obj = SCIPvarGetObj(shiftvar);
        if( (SCIPvarGetType(shiftvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(shiftvar) == SCIP_VARTYPE_INTEGER)
                && oldsolvalisfrac )
        {
            assert(SCIPisFeasIntegral(scip, newsolval));
            nfrac--;
            nnonimprovingshifts = 0;
            minnviolrows = INT_MAX;
            addFracCounter(nfracsinrow, nlprows, shiftvar, -1);

            /* the rounding was already calculated into the minobj -> update only if rounding in "wrong" direction */
            if( obj > 0.0 && newsolval > oldsolval )
                minobj += obj;
            else if( obj < 0.0 && newsolval < oldsolval )
                minobj -= obj;
        }
        else
        {
            /* update minimal possible objective value */
            minobj += obj * (newsolval - oldsolval);
        }

        /* update increase/decrease arrays */
        if( !oldsolvalisfrac )
        {
            probindex = SCIPvarGetProbindex(shiftvar);
            assert(0 <= probindex && probindex < nvars);
            increaseweight *= WEIGHTFACTOR;
            if( newsolval < oldsolval )
                ndecreases[probindex] += increaseweight;
            else
                nincreases[probindex] += increaseweight;
            if( increaseweight >= 1e+09 )
            {
                int i;

                for( i = 0; i < nvars; ++i )
                {
                    nincreases[i] /= increaseweight;
                    ndecreases[i] /= increaseweight;
                }
                increaseweight = 1.0;
            }
        }

        SCIPdebugMessage("shifting heuristic:  -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
                         nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
    }

    /* check, if the new solution is feasible */
    if( nfrac == 0 && nviolrows == 0 )
    {
        SCIP_Bool stored;

        /* check solution for feasibility, and add it to solution store if possible
         * neither integrality nor feasibility of LP rows has to be checked, because this is already
         * done in the shifting heuristic itself; however, we better check feasibility of LP rows,
         * because of numerical problems with activity updating
         */
        SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) );

        if( stored )
        {
            SCIPdebugMessage("found feasible shifted solution:\n");
            SCIPdebug( SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ) );
            *result = SCIP_FOUNDSOL;
        }
    }

    /* free memory buffers */
    SCIPfreeBufferArray(scip, &ndecreases);
    SCIPfreeBufferArray(scip, &nincreases);
    SCIPfreeBufferArray(scip, &nfracsinrow);
    SCIPfreeBufferArray(scip, &violrowpos);
    SCIPfreeBufferArray(scip, &violrows);
    SCIPfreeBufferArray(scip, &activities);

    return SCIP_OKAY;
}
Exemple #13
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecRounding) /*lint --e{715}*/
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_SOL* sol;
   SCIP_VAR** lpcands;
   SCIP_Real* lpcandssol;
   SCIP_ROW** lprows;
   SCIP_Real* activities;
   SCIP_ROW** violrows;
   int* violrowpos;
   SCIP_Real obj;
   SCIP_Real bestroundval;
   SCIP_Real minobj;
   int nlpcands;
   int nlprows;
   int nfrac;
   int nviolrows;
   int c;
   int r;
   SCIP_Longint nlps;
   SCIP_Longint ncalls;
   SCIP_Longint nsolsfound;
   SCIP_Longint nnodes;

   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(scip != NULL);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DIDNOTRUN;

   /* only call heuristic, if an optimal LP solution is at hand */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* get heuristic data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* don't call heuristic, if we have already processed the current LP solution */
   nlps = SCIPgetNLPs(scip);
   if( nlps == heurdata->lastlp )
      return SCIP_OKAY;
   heurdata->lastlp = nlps;

   /* don't call heuristic, if it was not successful enough in the past */
   ncalls = SCIPheurGetNCalls(heur);
   nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + SCIPheurGetNSolsFound(heur);
   nnodes = SCIPgetNNodes(scip);
   if( nnodes % ((ncalls/heurdata->successfactor)/(nsolsfound+1)+1) != 0 )
      return SCIP_OKAY;

   /* get fractional variables, that should be integral */
   SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, &lpcandssol, NULL, &nlpcands, NULL, NULL) );
   nfrac = nlpcands;

   /* only call heuristic, if LP solution is fractional */
   if( nfrac == 0 )
      return SCIP_OKAY;

   *result = SCIP_DIDNOTFIND;

   /* get LP rows */
   SCIP_CALL( SCIPgetLPRowsData(scip, &lprows, &nlprows) );

   SCIPdebugMessage("executing rounding heuristic: %d LP rows, %d fractionals\n", nlprows, nfrac);

   /* get memory for activities, violated rows, and row violation positions */
   SCIP_CALL( SCIPallocBufferArray(scip, &activities, nlprows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &violrows, nlprows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &violrowpos, nlprows) );

   /* get the activities for all globally valid rows;
    * the rows should be feasible, but due to numerical inaccuracies in the LP solver, they can be violated
    */
   nviolrows = 0;
   for( r = 0; r < nlprows; ++r )
   {
      SCIP_ROW* row;

      row = lprows[r];
      assert(SCIProwGetLPPos(row) == r);

      if( !SCIProwIsLocal(row) )
      {
         activities[r] = SCIPgetRowActivity(scip, row);
         if( SCIPisFeasLT(scip, activities[r], SCIProwGetLhs(row))
            || SCIPisFeasGT(scip, activities[r], SCIProwGetRhs(row)) )
         {
            violrows[nviolrows] = row;
            violrowpos[r] = nviolrows;
            nviolrows++;
         }
         else
            violrowpos[r] = -1;
      }
   }

   /* get the working solution from heuristic's local data */
   sol = heurdata->sol;
   assert(sol != NULL);

   /* copy the current LP solution to the working solution */
   SCIP_CALL( SCIPlinkLPSol(scip, sol) );

   /* calculate the minimal objective value possible after rounding fractional variables */
   minobj = SCIPgetSolTransObj(scip, sol);
   assert(minobj < SCIPgetCutoffbound(scip));
   for( c = 0; c < nlpcands; ++c )
   {
      obj = SCIPvarGetObj(lpcands[c]);
      bestroundval = obj > 0.0 ? SCIPfeasFloor(scip, lpcandssol[c]) : SCIPfeasCeil(scip, lpcandssol[c]);
      minobj += obj * (bestroundval - lpcandssol[c]);
   }

   /* try to round remaining variables in order to become/stay feasible */
   while( nfrac > 0 )
   {
      SCIP_VAR* roundvar;
      SCIP_Real oldsolval;
      SCIP_Real newsolval;

      SCIPdebugMessage("rounding heuristic: nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
         nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));

      /* minobj < SCIPgetCutoffbound(scip) should be true, otherwise the rounding variable selection
       * should have returned NULL. Due to possible cancellation we use SCIPisLE. */
      assert( SCIPisLE(scip, minobj, SCIPgetCutoffbound(scip)) );

      /* choose next variable to process:
       *  - if a violated row exists, round a variable decreasing the violation, that has least impact on other rows
       *  - otherwise, round a variable, that has strongest devastating impact on rows in opposite direction
       */
      if( nviolrows > 0 )
      {
         SCIP_ROW* row;
         int rowpos;

         row = violrows[nviolrows-1];
         rowpos = SCIProwGetLPPos(row);
         assert(0 <= rowpos && rowpos < nlprows);
         assert(violrowpos[rowpos] == nviolrows-1);

         SCIPdebugMessage("rounding heuristic: try to fix violated row <%s>: %g <= %g <= %g\n",
            SCIProwGetName(row), SCIProwGetLhs(row), activities[rowpos], SCIProwGetRhs(row));
         if( SCIPisFeasLT(scip, activities[rowpos], SCIProwGetLhs(row)) )
         {
            /* lhs is violated: select a variable rounding, that increases the activity */
            SCIP_CALL( selectIncreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
         }
         else
         {
            assert(SCIPisFeasGT(scip, activities[rowpos], SCIProwGetRhs(row)));
            /* rhs is violated: select a variable rounding, that decreases the activity */
            SCIP_CALL( selectDecreaseRounding(scip, sol, minobj, row, &roundvar, &oldsolval, &newsolval) );
         }
      }
      else
      {
         SCIPdebugMessage("rounding heuristic: search rounding variable and try to stay feasible\n");
         SCIP_CALL( selectEssentialRounding(scip, sol, minobj, lpcands, nlpcands, &roundvar, &oldsolval, &newsolval) );
      }

      /* check, whether rounding was possible */
      if( roundvar == NULL )
      {
         SCIPdebugMessage("rounding heuristic:  -> didn't find a rounding variable\n");
         break;
      }

      SCIPdebugMessage("rounding heuristic:  -> round var <%s>, oldval=%g, newval=%g, obj=%g\n",
         SCIPvarGetName(roundvar), oldsolval, newsolval, SCIPvarGetObj(roundvar));

      /* update row activities of globally valid rows */
      SCIP_CALL( updateActivities(scip, activities, violrows, violrowpos, &nviolrows, nlprows, 
            roundvar, oldsolval, newsolval) );

      /* store new solution value and decrease fractionality counter */
      SCIP_CALL( SCIPsetSolVal(scip, sol, roundvar, newsolval) );
      nfrac--;

      /* update minimal objective value possible after rounding remaining variables */
      obj = SCIPvarGetObj(roundvar);
      if( obj > 0.0 && newsolval > oldsolval )
         minobj += obj;
      else if( obj < 0.0 && newsolval < oldsolval )
         minobj -= obj;

      SCIPdebugMessage("rounding heuristic:  -> nfrac=%d, nviolrows=%d, obj=%g (best possible obj: %g)\n",
         nfrac, nviolrows, SCIPgetSolOrigObj(scip, sol), SCIPretransformObj(scip, minobj));
   }

   /* check, if the new solution is feasible */
   if( nfrac == 0 && nviolrows == 0 )
   {
      SCIP_Bool stored;

      /* check solution for feasibility, and add it to solution store if possible
       * neither integrality nor feasibility of LP rows has to be checked, because this is already
       * done in the rounding heuristic itself; however, be better check feasibility of LP rows,
       * because of numerical problems with activity updating
       */
      SCIP_CALL( SCIPtrySol(scip, sol, FALSE, FALSE, FALSE, TRUE, &stored) );

      if( stored )
      {
#ifdef SCIP_DEBUG
         SCIPdebugMessage("found feasible rounded solution:\n");
         SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) );
#endif
         *result = SCIP_FOUNDSOL;
      }
   }

   /* free memory buffers */
   SCIPfreeBufferArray(scip, &violrowpos);
   SCIPfreeBufferArray(scip, &violrows);
   SCIPfreeBufferArray(scip, &activities);

   return SCIP_OKAY;
}
Exemple #14
0
/** execution method of primal heuristic */
static
SCIP_DECL_HEUREXEC(heurExecRootsoldiving) /*lint --e{715}*/
{  /*lint --e{715}*/
   SCIP_HEURDATA* heurdata;
   SCIP_VAR** vars;
   SCIP_Real* rootsol;
   SCIP_Real* objchgvals;
   int* softroundings;
   int* intvalrounds;
   int nvars;
   int nbinvars;
   int nintvars;
   int nlpcands;
   SCIP_LPSOLSTAT lpsolstat;
   SCIP_Real absstartobjval;
   SCIP_Real objstep;
   SCIP_Real alpha;
   SCIP_Real oldobj;
   SCIP_Real newobj;
   SCIP_Bool lperror;
   SCIP_Bool lpsolchanged;
   SCIP_Longint nsolsfound;
   SCIP_Longint ncalls;
   SCIP_Longint nlpiterations;
   SCIP_Longint maxnlpiterations;
   int depth;
   int maxdepth;
   int maxdivedepth;
   int divedepth;
   int startnlpcands;
   int ncycles;
   int i;

   assert(heur != NULL);
   assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
   assert(scip != NULL);
   assert(result != NULL);
   assert(SCIPhasCurrentNodeLP(scip));

   *result = SCIP_DELAYED;

   /* do not call heuristic of node was already detected to be infeasible */
   if( nodeinfeasible )
      return SCIP_OKAY;

   /* only call heuristic, if an optimal LP solution is at hand */
   if( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
   if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
      return SCIP_OKAY;

   /* only call heuristic, if the LP solution is basic (which allows fast resolve in diving) */
   if( !SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* don't dive two times at the same node */
   if( SCIPgetLastDivenode(scip) == SCIPgetNNodes(scip) && SCIPgetDepth(scip) > 0 )
      return SCIP_OKAY;

   *result = SCIP_DIDNOTRUN;

   /* get heuristic's data */
   heurdata = SCIPheurGetData(heur);
   assert(heurdata != NULL);

   /* only apply heuristic, if only a few solutions have been found */
   if( heurdata->maxsols >= 0 && SCIPgetNSolsFound(scip) >= heurdata->maxsols )
      return SCIP_OKAY;

   /* only try to dive, if we are in the correct part of the tree, given by minreldepth and maxreldepth */
   depth = SCIPgetDepth(scip);
   maxdepth = SCIPgetMaxDepth(scip);
   maxdepth = MAX(maxdepth, 30);
   if( depth < heurdata->minreldepth*maxdepth || depth > heurdata->maxreldepth*maxdepth )
      return SCIP_OKAY;

   /* calculate the maximal number of LP iterations until heuristic is aborted */
   nlpiterations = SCIPgetNNodeLPIterations(scip);
   ncalls = SCIPheurGetNCalls(heur);
   nsolsfound = 10*SCIPheurGetNBestSolsFound(heur) + heurdata->nsuccess;
   maxnlpiterations = (SCIP_Longint)((1.0 + 10.0*(nsolsfound+1.0)/(ncalls+1.0)) * heurdata->maxlpiterquot * nlpiterations);
   maxnlpiterations += heurdata->maxlpiterofs;

   /* don't try to dive, if we took too many LP iterations during diving */
   if( heurdata->nlpiterations >= maxnlpiterations )
      return SCIP_OKAY;

   /* allow at least a certain number of LP iterations in this dive */
   maxnlpiterations = MAX(maxnlpiterations, heurdata->nlpiterations + MINLPITER);

   /* get number of fractional variables, that should be integral */
   nlpcands = SCIPgetNLPBranchCands(scip);

   /* don't try to dive, if there are no fractional variables */
   if( nlpcands == 0 )
      return SCIP_OKAY;

   /* calculate the maximal diving depth */
   nvars = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
   if( SCIPgetNSolsFound(scip) == 0 )
      maxdivedepth = (int)(heurdata->depthfacnosol * nvars);
   else
      maxdivedepth = (int)(heurdata->depthfac * nvars);
   maxdivedepth = MAX(maxdivedepth, 10);

   *result = SCIP_DIDNOTFIND;

   /* get all variables of LP */
   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, NULL, NULL) );

   /* get root solution value of all binary and integer variables */
   SCIP_CALL( SCIPallocBufferArray(scip, &rootsol, nbinvars + nintvars) );
   for( i = 0; i < nbinvars + nintvars; i++ )
      rootsol[i] = SCIPvarGetRootSol(vars[i]);

   /* get current LP objective value, and calculate length of a single step in an objective coefficient */
   absstartobjval = SCIPgetLPObjval(scip);
   absstartobjval = ABS(absstartobjval);
   absstartobjval = MAX(absstartobjval, 1.0);
   objstep = absstartobjval / 10.0;

   /* initialize array storing the preferred soft rounding directions and counting the integral value rounds */
   SCIP_CALL( SCIPallocBufferArray(scip, &softroundings, nbinvars + nintvars) );
   BMSclearMemoryArray(softroundings, nbinvars + nintvars);
   SCIP_CALL( SCIPallocBufferArray(scip, &intvalrounds, nbinvars + nintvars) );
   BMSclearMemoryArray(intvalrounds, nbinvars + nintvars);

   /* allocate temporary memory for buffering objective changes */
   SCIP_CALL( SCIPallocBufferArray(scip, &objchgvals, nbinvars + nintvars) );

   /* start diving */
   SCIP_CALL( SCIPstartDive(scip) );

   SCIPdebugMessage("(node %"SCIP_LONGINT_FORMAT") executing rootsoldiving heuristic: depth=%d, %d fractionals, dualbound=%g, maxnlpiterations=%"SCIP_LONGINT_FORMAT", maxdivedepth=%d, LPobj=%g, objstep=%g\n",
      SCIPgetNNodes(scip), SCIPgetDepth(scip), nlpcands, SCIPgetDualbound(scip), maxnlpiterations, maxdivedepth,
      SCIPgetLPObjval(scip), objstep);

   lperror = FALSE;
   divedepth = 0;
   lpsolstat = SCIP_LPSOLSTAT_OPTIMAL;
   alpha = heurdata->alpha;
   ncycles = 0;
   lpsolchanged = TRUE;
   startnlpcands = nlpcands;
   while( !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL && nlpcands > 0 && ncycles < 10
      && (divedepth < 10
         || nlpcands <= startnlpcands - divedepth/2
         || (divedepth < maxdivedepth && heurdata->nlpiterations < maxnlpiterations))
      && !SCIPisStopped(scip) )
   {
      SCIP_Bool success;
      int hardroundingidx;
      int hardroundingdir;
      SCIP_Real hardroundingoldbd;
      SCIP_Real hardroundingnewbd;
      SCIP_Bool boundschanged;

      SCIP_RETCODE retcode;

      /* create solution from diving LP and try to round it */
      SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
      SCIP_CALL( SCIProundSol(scip, heurdata->sol, &success) );

      if( success )
      {
         SCIPdebugMessage("rootsoldiving found roundable primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));

         /* try to add solution to SCIP */
         SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

         /* check, if solution was feasible and good enough */
         if( success )
         {
            SCIPdebugMessage(" -> solution was feasible and good enough\n");
            *result = SCIP_FOUNDSOL;
         }
      }

      divedepth++;
      hardroundingidx = -1;
      hardroundingdir = 0;
      hardroundingoldbd = 0.0;
      hardroundingnewbd = 0.0;
      boundschanged = FALSE;

      SCIPdebugMessage("dive %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT":\n", divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations);

      /* round solution x* from diving LP:
       *   - x~_j = down(x*_j)    if x*_j is integer or binary variable and x*_j <= root solution_j
       *   - x~_j = up(x*_j)      if x*_j is integer or binary variable and x*_j  > root solution_j
       *   - x~_j = x*_j          if x*_j is continuous variable
       * change objective function in diving LP:
       *   - if x*_j is integral, or j is a continuous variable, set obj'_j = alpha * obj_j
       *   - otherwise, set obj'_j = alpha * obj_j + sign(x*_j - x~_j)
       */
      for( i = 0; i < nbinvars + nintvars; i++ )
      {
         SCIP_VAR* var;
         SCIP_Real solval;

         var = vars[i];
         oldobj = SCIPgetVarObjDive(scip, var);
         newobj = oldobj;

         solval =  SCIPvarGetLPSol(var);
         if( SCIPisFeasIntegral(scip, solval) )
         {
            /* if the variable became integral after a soft rounding, count the rounds; after a while, fix it to its
             * current integral value;
             * otherwise, fade out the objective value
             */
            if( softroundings[i] != 0 && lpsolchanged )
            {
               intvalrounds[i]++;
               if( intvalrounds[i] == 5 && SCIPgetVarLbDive(scip, var) < SCIPgetVarUbDive(scip, var) - 0.5 )
               {
                  /* use exact integral value, if the variable is only integral within numerical tolerances */
                  solval = SCIPfloor(scip, solval+0.5);
                  SCIPdebugMessage(" -> fixing <%s> = %g\n", SCIPvarGetName(var), solval);
                  SCIP_CALL( SCIPchgVarLbDive(scip, var, solval) );
                  SCIP_CALL( SCIPchgVarUbDive(scip, var, solval) );
                  boundschanged = TRUE;
               }
            }
            else
               newobj = alpha * oldobj;
         }
         else if( solval <= rootsol[i] )
         {
            /* if the variable was soft rounded most of the time downwards, round it downwards by changing the bounds;
             * otherwise, apply soft rounding by changing the objective value
             */
            softroundings[i]--;
            if( softroundings[i] <= -10 && hardroundingidx == -1 )
            {
               SCIPdebugMessage(" -> hard rounding <%s>[%g] <= %g\n",
                  SCIPvarGetName(var), solval, SCIPfeasFloor(scip, solval));
               hardroundingidx = i;
               hardroundingdir = -1;
               hardroundingoldbd = SCIPgetVarUbDive(scip, var);
               hardroundingnewbd = SCIPfeasFloor(scip, solval);
               SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd) );
               boundschanged = TRUE;
            }
            else
               newobj = alpha * oldobj + objstep;
         }
         else
         {
            /* if the variable was soft rounded most of the time upwards, round it upwards by changing the bounds;
             * otherwise, apply soft rounding by changing the objective value
             */
            softroundings[i]++;
            if( softroundings[i] >= +10 && hardroundingidx == -1 )
            {
               SCIPdebugMessage(" -> hard rounding <%s>[%g] >= %g\n",
                  SCIPvarGetName(var), solval, SCIPfeasCeil(scip, solval));
               hardroundingidx = i;
               hardroundingdir = +1;
               hardroundingoldbd = SCIPgetVarLbDive(scip, var);
               hardroundingnewbd = SCIPfeasCeil(scip, solval);
               SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd) );
               boundschanged = TRUE;
            }
            else
               newobj = alpha * oldobj - objstep;
         }

         /* remember the objective change */
         objchgvals[i] = newobj;
      }

      /* apply objective changes if there was no bound change */
      if( !boundschanged )
      {
         /* apply cached changes on integer variables */
         for( i = 0; i < nbinvars + nintvars; ++i )
         {
            SCIP_VAR* var;

            var = vars[i];
            SCIPdebugMessage(" -> i=%d  var <%s>, solval=%g, rootsol=%g, oldobj=%g, newobj=%g\n",
               i, SCIPvarGetName(var), SCIPvarGetLPSol(var), rootsol[i], SCIPgetVarObjDive(scip, var), objchgvals[i]);

            SCIP_CALL( SCIPchgVarObjDive(scip, var, objchgvals[i]) );
         }

         /* fade out the objective values of the continuous variables */
         for( i = nbinvars + nintvars; i < nvars; i++ )
         {
            SCIP_VAR* var;

            var = vars[i];
            oldobj = SCIPgetVarObjDive(scip, var);
            newobj = alpha * oldobj;

            SCIPdebugMessage(" -> i=%d  var <%s>, solval=%g, oldobj=%g, newobj=%g\n",
               i, SCIPvarGetName(var), SCIPvarGetLPSol(var), oldobj, newobj);

            SCIP_CALL( SCIPchgVarObjDive(scip, var, newobj) );
         }
      }

   SOLVEAGAIN:
      /* resolve the diving LP */
      nlpiterations = SCIPgetNLPIterations(scip);

      retcode = SCIPsolveDiveLP(scip,  MAX((int)(maxnlpiterations - heurdata->nlpiterations), MINLPITER), &lperror, NULL);
      lpsolstat = SCIPgetLPSolstat(scip);

      /* Errors in the LP solver should not kill the overall solving process, if the LP is just needed for a heuristic.
       * Hence in optimized mode, the return code is caught and a warning is printed, only in debug mode, SCIP will stop.
       */
      if( retcode != SCIP_OKAY )
      {
#ifndef NDEBUG
         if( lpsolstat != SCIP_LPSOLSTAT_UNBOUNDEDRAY )
         {
            SCIP_CALL( retcode );
         }
#endif
         SCIPwarningMessage(scip, "Error while solving LP in Rootsoldiving heuristic; LP solve terminated with code <%d>\n", retcode);
         SCIPwarningMessage(scip, "This does not affect the remaining solution procedure --> continue\n");
      }

      if( lperror )
         break;

      /* update iteration count */
      heurdata->nlpiterations += SCIPgetNLPIterations(scip) - nlpiterations;

      /* if no LP iterations were performed, we stayed at the same solution -> count this cycling */
      lpsolchanged = (SCIPgetNLPIterations(scip) != nlpiterations);
      if( lpsolchanged )
         ncycles = 0;
      else if( !boundschanged ) /* do not count if integral variables have been fixed */
         ncycles++;

      /* get LP solution status and number of fractional variables, that should be integral */
      if( lpsolstat == SCIP_LPSOLSTAT_INFEASIBLE && hardroundingidx != -1 )
      {
         SCIP_VAR* var;

         var = vars[hardroundingidx];

         /* round the hard rounded variable to the opposite direction and resolve the LP */
         if( hardroundingdir == -1 )
         {
            SCIPdebugMessage(" -> opposite hard rounding <%s> >= %g\n", SCIPvarGetName(var), hardroundingnewbd + 1.0);
            SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingoldbd) );
            SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingnewbd + 1.0) );
         }
         else
         {
            SCIPdebugMessage(" -> opposite hard rounding <%s> <= %g\n", SCIPvarGetName(var), hardroundingnewbd - 1.0);
            SCIP_CALL( SCIPchgVarLbDive(scip, var, hardroundingoldbd) );
            SCIP_CALL( SCIPchgVarUbDive(scip, var, hardroundingnewbd - 1.0) );
         }
         hardroundingidx = -1;
         goto SOLVEAGAIN;
      }
      if( lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
         nlpcands = SCIPgetNLPBranchCands(scip);
      SCIPdebugMessage("   -> lpsolstat=%d, nfrac=%d\n", lpsolstat, nlpcands);
   }

   SCIPdebugMessage("---> diving finished: lpsolstat = %d, depth %d/%d, LP iter %"SCIP_LONGINT_FORMAT"/%"SCIP_LONGINT_FORMAT"\n",
      lpsolstat, divedepth, maxdivedepth, heurdata->nlpiterations, maxnlpiterations);

   /* check if a solution has been found */
   if( nlpcands == 0 && !lperror && lpsolstat == SCIP_LPSOLSTAT_OPTIMAL )
   {
      SCIP_Bool success;

      /* create solution from diving LP */
      SCIP_CALL( SCIPlinkLPSol(scip, heurdata->sol) );
      SCIPdebugMessage("rootsoldiving found primal solution: obj=%g\n", SCIPgetSolOrigObj(scip, heurdata->sol));

      /* try to add solution to SCIP */
      SCIP_CALL( SCIPtrySol(scip, heurdata->sol, FALSE, FALSE, FALSE, FALSE, &success) );

      /* check, if solution was feasible and good enough */
      if( success )
      {
         SCIPdebugMessage(" -> solution was feasible and good enough\n");
         *result = SCIP_FOUNDSOL;
      }
   }

   /* end diving */
   SCIP_CALL( SCIPendDive(scip) );

   if( *result == SCIP_FOUNDSOL )
      heurdata->nsuccess++;

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &objchgvals);
   SCIPfreeBufferArray(scip, &intvalrounds);
   SCIPfreeBufferArray(scip, &softroundings);
   SCIPfreeBufferArray(scip, &rootsol);

   SCIPdebugMessage("rootsoldiving heuristic finished\n");

   return SCIP_OKAY;
}