示例#1
0
/** adds cut to separation storage and captures it;
 *  if the cut should be forced to enter the LP, an infinite score has to be used
 */
SCIP_RETCODE SCIPsepastoreAddCut(
   SCIP_SEPASTORE*       sepastore,          /**< separation storage */
   BMS_BLKMEM*           blkmem,             /**< block memory */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_STAT*            stat,               /**< problem statistics data */
   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
   SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global events */
   SCIP_LP*              lp,                 /**< LP data */
   SCIP_SOL*             sol,                /**< primal solution that was separated, or NULL for LP solution */
   SCIP_ROW*             cut,                /**< separated cut */
   SCIP_Bool             forcecut,           /**< should the cut be forced to enter the LP? */
   SCIP_Bool             root                /**< are we at the root node? */
   )
{
   assert(sepastore != NULL);
   assert(cut != NULL);
   assert(!SCIProwIsInLP(cut));
   assert(!SCIPsetIsInfinity(set, -SCIProwGetLhs(cut)) || !SCIPsetIsInfinity(set, SCIProwGetRhs(cut)));

   /* debug: check cut for feasibility */
   SCIP_CALL( SCIPdebugCheckRow(set, cut) ); /*lint !e506 !e774*/

   /* update statistics of total number of found cuts */
   if( !sepastore->initiallp )
   {
      sepastore->ncutsfound++;
      sepastore->ncutsfoundround++;
   }

   /* add LP row cut to separation storage */
   SCIP_CALL( sepastoreAddCut(sepastore, blkmem, set, stat, eventqueue, eventfilter, lp, sol, cut, forcecut, root) );

   return SCIP_OKAY;
}
示例#2
0
/** computes score for current LP solution and initialized orthogonalities */
static
SCIP_RETCODE computeScore(
   SCIP_SEPASTORE*       sepastore,          /**< separation storage */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_STAT*            stat,               /**< problem statistics */
   SCIP_LP*              lp,                 /**< LP data */
   SCIP_Bool             handlepool,         /**< whether the efficacy of cuts in the pool should be reduced  */
   int                   pos                 /**< position of cut to handle */
   )
{
   SCIP_ROW* cut;
   SCIP_Real cutefficacy;
   SCIP_Real cutscore;

   cut = sepastore->cuts[pos];

   /* calculate cut's efficacy */
   cutefficacy = SCIProwGetLPEfficacy(cut, set, stat, lp);
   
   /* If a cut is not member of the cut pool, we slightly decrease its score to prefer identical
    * cuts which are in the cut pool.  This is because the conversion of cuts into linear
    * constraints after a restart looks at the cut pool and cannot find tight non-pool cuts.
    */
   if( handlepool && !SCIProwIsInGlobalCutpool(cut) )
      cutefficacy *= 0.9999;

   /* calculate resulting score */
   assert( sepastore->objparallelisms[pos] != SCIP_INVALID ); /*lint !e777*/
   cutscore = cutefficacy + set->sepa_objparalfac * sepastore->objparallelisms[pos] + set->sepa_orthofac * 1.0;
   assert( !SCIPsetIsInfinity(set, cutscore) );

   sepastore->efficacies[pos] = cutefficacy;
   sepastore->scores[pos] = cutscore;

   /* make sure that the orthogonalities are initialized to 1.0 */
   sepastore->orthogonalities[pos] = 1.0;

   return SCIP_OKAY;
}
示例#3
0
文件: stat.c 项目: hhexiy/scip
/** update the primal-dual integral statistic. method accepts + and - SCIPsetInfinity() as values for
 *  upper and lower bound, respectively
 */
void SCIPstatUpdatePrimalDualIntegral(
   SCIP_STAT*            stat,               /**< problem statistics data */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_PROB*            transprob,          /**< transformed problem */
   SCIP_PROB*            origprob,           /**< original problem */
   SCIP_Real             upperbound,         /**< current upper bound in transformed problem, or infinity */
   SCIP_Real             lowerbound          /**< current lower bound in transformed space, or -infinity */
   )
{
   SCIP_Real currentgap;
   SCIP_Real solvingtime;
   SCIP_Real primalbound;
   SCIP_Real dualbound;

   assert(stat != NULL);
   assert(set != NULL);

   solvingtime = SCIPclockGetTime(stat->solvingtime);
   assert(solvingtime >= stat->previntegralevaltime);

   if( !SCIPsetIsInfinity(set, upperbound) ) /*lint !e777*/
   {
      /* get value in original space for gap calculation */
      primalbound = SCIPprobExternObjval(transprob, origprob, set, upperbound);

      if( SCIPsetIsZero(set, primalbound) )
         primalbound = 0.0;
   }
   else
   {
      /* no new upper bound: use stored values from last update */
      upperbound = stat->lastupperbound;
      primalbound = stat->lastprimalbound;
      assert(SCIPsetIsZero(set, primalbound) == (primalbound == 0.0)); /*lint !e777*/
   }

   if( !SCIPsetIsInfinity(set, -lowerbound) ) /*lint !e777*/
   {
      /* get value in original space for gap calculation */
      dualbound = SCIPprobExternObjval(transprob, origprob, set, lowerbound);

      if( SCIPsetIsZero(set, dualbound) )
         dualbound = 0.0;
   }
   else
   {
      /* no new lower bound: use stored values from last update */
      lowerbound = stat->lastlowerbound;
      dualbound = stat->lastdualbound;
      assert(SCIPsetIsZero(set, dualbound) == (dualbound == 0.0)); /*lint !e777*/
   }

   /* computation of the gap, special cases are handled first */
   if( primalbound == SCIP_UNKNOWN || dualbound == SCIP_UNKNOWN ) /*lint !e777*/
      currentgap = 100.0;
   /* the gap is 0.0 if bounds coincide */
   else if( SCIPsetIsGE(set, lowerbound, upperbound) || SCIPsetIsEQ(set, primalbound, dualbound) )
      currentgap = 0.0;
   /* the gap is 100.0 if bounds have different signs */
   else if( primalbound * dualbound <= 0.0 ) /*lint !e777*/
      currentgap = 100.0;
   else if( !SCIPsetIsInfinity(set, REALABS(primalbound)) && !SCIPsetIsInfinity(set, REALABS(dualbound)) )
   {
      SCIP_Real absprim = REALABS(primalbound);
      SCIP_Real absdual = REALABS(dualbound);

      /* The gap in the definition of the primal-dual integral differs from the default SCIP gap function.
       * Here, the MAX(primalbound, dualbound) is taken for gap quotient in order to ensure a gap <= 100.
       */
      currentgap = 100.0 * REALABS(primalbound - dualbound) / MAX(absprim, absdual);
      assert(SCIPsetIsLE(set, currentgap, 100.0));
   }
   else
      currentgap = 100.0;

   /* if primal and dual bound have opposite signs, the gap always evaluates to 100.0% */
   assert(currentgap == 0.0 || currentgap == 100.0 || SCIPsetIsGE(set, primalbound * dualbound, 0.0));
   assert(SCIPsetIsGE(set, stat->previousgap, currentgap) || (set->stage == SCIP_STAGE_EXITPRESOLVE
         && SCIPsetIsFeasGE(set, stat->previousgap, currentgap)));

   /* update the integral based on previous information */
   stat->primaldualintegral += (solvingtime - stat->previntegralevaltime) * stat->previousgap;

   /* update all relevant information for next evaluation */
   stat->previousgap = currentgap;
   stat->previntegralevaltime = solvingtime;
   stat->lastprimalbound = primalbound;
   stat->lastdualbound = dualbound;
   stat->lastlowerbound = lowerbound;
   stat->lastupperbound = upperbound;
}
示例#4
0
/** adds cuts to the LP and clears separation storage */
SCIP_RETCODE SCIPsepastoreApplyCuts(
   SCIP_SEPASTORE*       sepastore,          /**< separation storage */
   BMS_BLKMEM*           blkmem,             /**< block memory */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_STAT*            stat,               /**< problem statistics */
   SCIP_TREE*            tree,               /**< branch and bound tree */
   SCIP_LP*              lp,                 /**< LP data */
   SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
   SCIP_EVENTFILTER*     eventfilter,        /**< global event filter */
   SCIP_Bool             root,               /**< are we at the root node? */
   SCIP_Bool*            cutoff              /**< pointer to store whether an empty domain was created */
   )
{
   SCIP_NODE* node;
   SCIP_Real mincutorthogonality;
   int depth;
   int maxsepacuts;
   int ncutsapplied;
   int pos;

   assert(sepastore != NULL);
   assert(set != NULL);
   assert(tree != NULL);
   assert(lp != NULL);
   assert(cutoff != NULL);

   *cutoff = FALSE;

   SCIPdebugMessage("applying %d cuts\n", sepastore->ncuts);

   node = SCIPtreeGetCurrentNode(tree);
   assert(node != NULL);

   /* get maximal number of cuts to add to the LP */
   maxsepacuts = SCIPsetGetSepaMaxcuts(set, root);
   ncutsapplied = 0;

   /* get depth of current node */
   depth = SCIPnodeGetDepth(node);

   /* calculate minimal cut orthogonality */
   mincutorthogonality = (root ? set->sepa_minorthoroot : set->sepa_minortho);
   mincutorthogonality = MAX(mincutorthogonality, set->num_epsilon);

   /* Compute scores for all non-forced cuts and initialize orthogonalities - make sure all cuts are initialized again for the current LP solution */
   for( pos = sepastore->nforcedcuts; pos < sepastore->ncuts; pos++ )
   {
      SCIP_CALL( computeScore(sepastore, set, stat, lp, TRUE, pos) );
   }

   /* apply all forced cuts */
   for( pos = 0; pos < sepastore->nforcedcuts && !(*cutoff); pos++ )
   {
      SCIP_ROW* cut;

      cut = sepastore->cuts[pos];
      assert(SCIPsetIsInfinity(set, sepastore->scores[pos]));

      /* if the cut is a bound change (i.e. a row with only one variable), add it as bound change instead of LP row */
      if( !SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1 )
      {
         SCIPdebugMessage(" -> applying forced cut <%s> as boundchange\n", SCIProwGetName(cut));
         SCIP_CALL( sepastoreApplyBdchg(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue, cut, cutoff) );
      }
      else
      {
         /* add cut to the LP and update orthogonalities */
         SCIPdebugMessage(" -> applying forced cut <%s>\n", SCIProwGetName(cut));
         /*SCIPdebug(SCIProwPrint(cut, NULL));*/
         SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, depth, &ncutsapplied) );
      }
   }

   /* apply non-forced cuts */
   while( ncutsapplied < maxsepacuts && sepastore->ncuts > sepastore->nforcedcuts && !(*cutoff) )
   {
      SCIP_ROW* cut;
      int bestpos;
      
      /* get best non-forced cut */
      bestpos = sepastoreGetBestCut(sepastore);
      assert(sepastore->nforcedcuts <= bestpos && bestpos < sepastore->ncuts);
      assert(sepastore->scores[bestpos] != SCIP_INVALID ); /*lint !e777*/
      assert(sepastore->efficacies[bestpos] != SCIP_INVALID ); /*lint !e777*/
      cut = sepastore->cuts[bestpos];
      assert(SCIProwIsModifiable(cut) || SCIProwGetNNonz(cut) != 1); /* bound changes are forced cuts */
      assert(!SCIPsetIsInfinity(set, sepastore->scores[bestpos]));
      
      SCIPdebugMessage(" -> applying cut <%s> (pos=%d/%d, len=%d, efficacy=%g, objparallelism=%g, orthogonality=%g, score=%g)\n",
         SCIProwGetName(cut), bestpos, sepastore->ncuts, SCIProwGetNNonz(cut), sepastore->efficacies[bestpos], sepastore->objparallelisms[bestpos],
         sepastore->orthogonalities[bestpos], sepastore->scores[bestpos]);
      /*SCIPdebug(SCIProwPrint(cut, NULL));*/

      /* capture cut such that it is not destroyed in sepastoreDelCut() */
      SCIProwCapture(cut);

      /* release the row and delete the cut (also issuing ROWDELETEDSEPA event) */
      SCIP_CALL( sepastoreDelCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, bestpos) );

      /* Do not add (non-forced) non-violated cuts.
       * Note: do not take SCIPsetIsEfficacious(), because constraint handlers often add cuts w.r.t. SCIPsetIsFeasPositive().
       */
      if( SCIPsetIsFeasPositive(set, sepastore->efficacies[bestpos]) )
      {
         /* add cut to the LP and update orthogonalities */
         SCIP_CALL( sepastoreApplyCut(sepastore, blkmem, set, eventqueue, eventfilter, lp, cut, mincutorthogonality, depth, &ncutsapplied) );
      }

      /* release cut */
      SCIP_CALL( SCIProwRelease(&cut, blkmem, set, lp) );
   }

   /* clear the separation storage and reset statistics for separation round */
   SCIP_CALL( SCIPsepastoreClearCuts(sepastore, blkmem, set, eventqueue, eventfilter, lp) );

   return SCIP_OKAY;
}
示例#5
0
/** applies a cut that is a bound change directly as bound change instead of adding it as row to the LP */
static
SCIP_RETCODE sepastoreApplyBdchg(
   SCIP_SEPASTORE*       sepastore,          /**< separation storage */
   BMS_BLKMEM*           blkmem,             /**< block memory */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_STAT*            stat,               /**< problem statistics */
   SCIP_TREE*            tree,               /**< branch and bound tree */
   SCIP_LP*              lp,                 /**< LP data */
   SCIP_BRANCHCAND*      branchcand,         /**< branching candidate storage */
   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
   SCIP_ROW*             cut,                /**< cut with a single variable */
   SCIP_Bool*            cutoff              /**< pointer to store whether an empty domain was created */
   )
{
   SCIP_COL** cols;
   SCIP_Real* vals;
   SCIP_VAR* var;
   SCIP_Real lhs;
   SCIP_Real rhs;

   assert(sepastore != NULL);
   assert(!SCIProwIsModifiable(cut));
   assert(SCIProwGetNNonz(cut) == 1);
   assert(cutoff != NULL);

   *cutoff = FALSE;

   /* get the single variable and its coefficient of the cut */
   cols = SCIProwGetCols(cut);
   assert(cols != NULL);
   var = SCIPcolGetVar(cols[0]);
   vals = SCIProwGetVals(cut);
   assert(vals != NULL);
   assert(!SCIPsetIsZero(set, vals[0]));

   /* if the coefficient is nearly zero, we better ignore this cut for numerical reasons */
   if( SCIPsetIsFeasZero(set, vals[0]) )
      return SCIP_OKAY;

   /* get the left hand side of the cut and convert it to a bound */
   lhs = SCIProwGetLhs(cut);
   if( !SCIPsetIsInfinity(set, -lhs) )
   {
      lhs -= SCIProwGetConstant(cut);
      if( vals[0] > 0.0 )
      {
         /* coefficient is positive -> lhs corresponds to lower bound */
         SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue,
               var, lhs/vals[0], cutoff) );
      }
      else
      {
         /* coefficient is negative -> lhs corresponds to upper bound */
         SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue,
               var, lhs/vals[0], cutoff) );
      }
   }

   /* get the right hand side of the cut and convert it to a bound */
   rhs = SCIProwGetRhs(cut);
   if( !SCIPsetIsInfinity(set, rhs) )
   {
      rhs -= SCIProwGetConstant(cut);
      if( vals[0] > 0.0 )
      {
         /* coefficient is positive -> rhs corresponds to upper bound */
         SCIP_CALL( sepastoreApplyUb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue,
               var, rhs/vals[0], cutoff) );
      }
      else
      {
         /* coefficient is negative -> rhs corresponds to lower bound */
         SCIP_CALL( sepastoreApplyLb(sepastore, blkmem, set, stat, tree, lp, branchcand, eventqueue,
               var, rhs/vals[0], cutoff) );
      }
   }

   /* count the bound change as applied cut */
   if( !sepastore->initiallp )
      sepastore->ncutsapplied++;

   return SCIP_OKAY;
}
示例#6
0
/** adds cut stored as LP row to separation storage and captures it;
 *  if the cut should be forced to be used, an infinite score has to be used
 */
static
SCIP_RETCODE sepastoreAddCut(
   SCIP_SEPASTORE*       sepastore,          /**< separation storage */
   BMS_BLKMEM*           blkmem,             /**< block memory */
   SCIP_SET*             set,                /**< global SCIP settings */
   SCIP_STAT*            stat,               /**< problem statistics data */
   SCIP_EVENTQUEUE*      eventqueue,         /**< event queue */
   SCIP_EVENTFILTER*     eventfilter,        /**< event filter for global events */
   SCIP_LP*              lp,                 /**< LP data */
   SCIP_SOL*             sol,                /**< primal solution that was separated, or NULL for LP solution */
   SCIP_ROW*             cut,                /**< separated cut */
   SCIP_Bool             forcecut,           /**< should the cut be forced to enter the LP? */
   SCIP_Bool             root                /**< are we at the root node? */
   )
{
   SCIP_Real cutefficacy;
   SCIP_Real cutobjparallelism;
   SCIP_Real cutscore;
   int pos;

   assert(sepastore != NULL);
   assert(sepastore->nforcedcuts <= sepastore->ncuts);
   assert(set != NULL);
   assert(cut != NULL);
   assert(sol != NULL || !SCIProwIsInLP(cut));
   assert(!SCIPsetIsInfinity(set, -SCIProwGetLhs(cut)) || !SCIPsetIsInfinity(set, SCIProwGetRhs(cut)));
   assert(eventqueue != NULL);
   assert(eventfilter != NULL);

   /* in the root node, every local cut is a global cut, and global cuts are nicer in many ways...*/
   if( root && SCIProwIsLocal(cut) )
   {
      SCIPdebugMessage("change local flag of cut <%s> to FALSE due to addition in root node\n", SCIProwGetName(cut));

      SCIP_CALL( SCIProwChgLocal(cut, FALSE) );

      assert(!SCIProwIsLocal(cut));
   }

   /* check cut for redundancy
    * in each separation round, make sure that at least one (even redundant) cut enters the LP to avoid cycling
    */
   if( !forcecut && sepastore->ncuts > 0 && sepastoreIsCutRedundant(sepastore, set, stat, cut) )
      return SCIP_OKAY;

   /* if only one cut is currently present in the cut store, it could be redundant; in this case, it can now be removed
    * again, because now a non redundant cut enters the store
    */
   if( sepastore->ncuts == 1 && sepastoreIsCutRedundant(sepastore, set, stat, sepastore->cuts[0]) )
   {
      /* check, if the row deletions from separation storage events are tracked
       * if so, issue ROWDELETEDSEPA event
       */
      if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWDELETEDSEPA) != 0 )
      {
         SCIP_EVENT* event;

         SCIP_CALL( SCIPeventCreateRowDeletedSepa(&event, blkmem, sepastore->cuts[0]) );
         SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
      }
      
      SCIP_CALL( SCIProwRelease(&sepastore->cuts[0], blkmem, set, lp) );
      sepastore->ncuts = 0;
      sepastore->nforcedcuts = 0;
   }

   /* a cut is forced to enter the LP if
    *  - we construct the initial LP, or
    *  - it has infinite score factor, or
    *  - it is a bound change
    * if it is a non-forced cut and no cuts should be added, abort
    */
   forcecut = forcecut || sepastore->initiallp || sepastore->forcecuts
      || (!SCIProwIsModifiable(cut) && SCIProwGetNNonz(cut) == 1);
   if( !forcecut && SCIPsetGetSepaMaxcuts(set, root) == 0 )
      return SCIP_OKAY;

   /* get enough memory to store the cut */
   SCIP_CALL( sepastoreEnsureCutsMem(sepastore, set, sepastore->ncuts+1) );
   assert(sepastore->ncuts < sepastore->cutssize);

   if( forcecut )
   {
      cutefficacy = SCIPsetInfinity(set);
      cutscore = SCIPsetInfinity(set);
      cutobjparallelism = 1.0;
   }
   else
   {
      /* initialize values to invalid (will be initialized during cut filtering) */
      cutefficacy = SCIP_INVALID;
      cutscore = SCIP_INVALID;

      /* initialize parallelism to objective (constant throughout filtering) */
      if( set->sepa_objparalfac > 0.0 )
         cutobjparallelism = SCIProwGetObjParallelism(cut, set, lp);
      else
         cutobjparallelism = 0.0; /* no need to calculate it */
   }

   SCIPdebugMessage("adding cut <%s> to separation storage of size %d (forcecut=%u, len=%d)\n",
      SCIProwGetName(cut), sepastore->ncuts, forcecut, SCIProwGetNNonz(cut));
   /*SCIPdebug(SCIProwPrint(cut, NULL));*/

   /* capture the cut */
   SCIProwCapture(cut);

   /* add cut to arrays */
   if( forcecut )
   {
      /* make room at the beginning of the array for forced cut */
      pos = sepastore->nforcedcuts;
      sepastore->cuts[sepastore->ncuts] = sepastore->cuts[pos];
      sepastore->efficacies[sepastore->ncuts] = sepastore->efficacies[pos];
      sepastore->objparallelisms[sepastore->ncuts] = sepastore->objparallelisms[pos];
      sepastore->orthogonalities[sepastore->ncuts] = sepastore->orthogonalities[pos];
      sepastore->scores[sepastore->ncuts] = sepastore->scores[pos];
      sepastore->nforcedcuts++;
   }
   else
      pos = sepastore->ncuts;

   sepastore->cuts[pos] = cut;
   sepastore->efficacies[pos] = cutefficacy;
   sepastore->objparallelisms[pos] = cutobjparallelism;
   sepastore->orthogonalities[pos] = 1.0;
   sepastore->scores[pos] = cutscore;
   sepastore->ncuts++;

   /* check, if the row addition to separation storage events are tracked
    * if so, issue ROWADDEDSEPA event
    */
   if( eventfilter->len > 0 && (eventfilter->eventmask & SCIP_EVENTTYPE_ROWADDEDSEPA) != 0 )
   {
      SCIP_EVENT* event;

      SCIP_CALL( SCIPeventCreateRowAddedSepa(&event, blkmem, cut) );
      SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, eventfilter, &event) );
   }

   return SCIP_OKAY;
}