示例#1
0
/** checks if a given branching candidate is better than a previous one and updates the best branching candidate accordingly */
static
SCIP_RETCODE updateBestCandidate(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_BRANCHRULEDATA*  branchruledata,     /**< branching rule data */
   SCIP_VAR**            bestvar,            /**< best branching candidate */
   SCIP_Real*            bestbrpoint,        /**< branching point for best branching candidate */
   SCIP_Real*            bestscore,          /**< score of best branching candidate */
   SCIP_VAR*             cand,               /**< branching candidate to consider */
   SCIP_Real             candscoremin,       /**< minimal score of branching candidate */
   SCIP_Real             candscoremax,       /**< maximal score of branching candidate */
   SCIP_Real             candscoresum,       /**< sum of scores of branching candidate */
   SCIP_Real             candsol             /**< proposed branching point of branching candidate */          
)
{
   SCIP_Real candbrpoint;
   SCIP_Real branchscore;

   SCIP_Real deltaminus;
   SCIP_Real deltaplus;

   SCIP_Real pscostdown;
   SCIP_Real pscostup;
   
   char strategy;

   assert(scip != NULL);
   assert(branchruledata != NULL);
   assert(bestvar != NULL);
   assert(bestbrpoint != NULL);
   assert(bestscore != NULL);
   assert(cand != NULL);

   /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */
   assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) ||
      SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR);
   
   if( SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR )
   {
      /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */
      SCIP_VAR** multvars;
      int nmultvars;
      int i;
      SCIP_Bool success;
      SCIP_Real multvarlb;
      SCIP_Real multvarub;

      cand = SCIPvarGetProbvar(cand);
      multvars = SCIPvarGetMultaggrVars(cand);
      nmultvars = SCIPvarGetMultaggrNVars(cand);

      /* if we have a candidate branching point, then first register only aggregation variables
       * for which we can compute a corresponding branching point too (see also comments below)
       * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol
       */
      success = FALSE;
      if( candsol != SCIP_INVALID ) /*lint !e777*/
      {
         SCIP_Real* multscalars;
         SCIP_Real minact;
         SCIP_Real maxact;
         SCIP_Real aggrvarsol;
         SCIP_Real aggrvarsol1;
         SCIP_Real aggrvarsol2;

         multscalars = SCIPvarGetMultaggrScalars(cand);

         /* for computing the branching point, we need the current bounds of the multi-aggregated variable */
         minact = SCIPcomputeVarLbLocal(scip, cand);
         maxact = SCIPcomputeVarUbLocal(scip, cand);

         for( i = 0; i < nmultvars; ++i )
         {
            /* skip fixed variables */
            multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
            multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
            if( SCIPisEQ(scip, multvarlb, multvarub) )
               continue;

            assert(multscalars != NULL);
            assert(multscalars[i] != 0.0);

            /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node
             * will be candsol by a clever choice for the branching point of multvars[i],
             * but we can try to ensure that at least one of them will be at candsol
             */
            if( multscalars[i] > 0.0 )
            {
               /*    cand >= candsol
                * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i]
                *                 = (candsol - maxact) / multscalars[i] + ub(multvars[i])
                */
               aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub;

               /*     cand <= candsol
                * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i]
                *                 = (candsol - minact) / multscalars[i] + lb(multvars[i])
                */
               aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb;
            }
            else
            {
               /*    cand >= candsol
                * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i]
                *                 = (candsol - maxact) / multscalars[i] + lb(multvars[i])
                */
               aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb;

               /*    cand <= candsol
                * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i]
                *                 = (candsol - minact) / multscalars[i] + ub(multvars[i])
                */
               aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub;
            }

            /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i])
             * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one
             * if both are out of bounds, then give up
             * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???)
             */
            if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) )
            {
               if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
                  continue;
               else
                  aggrvarsol = aggrvarsol2;
            }
            else
            {
               if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
                  aggrvarsol = aggrvarsol1;
               else
                  aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2;
            }
            success = TRUE;

            SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore,
                  multvars[i], candscoremin, candscoremax, candscoresum, aggrvarsol) );
         }
      }

      if( !success )
         for( i = 0; i < nmultvars; ++i )
         {
            /* skip fixed variables */
            multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
            multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
            if( SCIPisEQ(scip, multvarlb, multvarub) )
               continue;

            SCIP_CALL( updateBestCandidate(scip, branchruledata, bestvar, bestbrpoint, bestscore,
               multvars[i], candscoremin, candscoremax, candscoresum, SCIP_INVALID) );
         }

      assert(*bestvar != NULL); /* if all variables were fixed, something is strange */
      
      return SCIP_OKAY;
   }
   
   /* select branching point for this variable */
   candbrpoint = SCIPgetBranchingPoint(scip, cand, candsol);
   assert(candbrpoint >= SCIPvarGetLbLocal(cand));
   assert(candbrpoint <= SCIPvarGetUbLocal(cand));

   /* we cannot branch on a huge value for a discrete variable, because we simply cannot enumerate such huge integer values in floating point
    * arithmetics
    */
   if( SCIPvarGetType(cand) != SCIP_VARTYPE_CONTINUOUS && (SCIPisHugeValue(scip, candbrpoint) || SCIPisHugeValue(scip, -candbrpoint)) )
      return SCIP_OKAY;

   assert(SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS || !SCIPisIntegral(scip, candbrpoint));

   if( SCIPvarGetType(cand) == SCIP_VARTYPE_CONTINUOUS )
      strategy = (branchruledata->strategy == 'u' ? branchruledata->updatestrategy : branchruledata->strategy);
   else
      strategy = (branchruledata->strategy == 'u' ? 'l' : branchruledata->strategy);

   switch( strategy )
   {
   case 'l':
      if( SCIPisInfinity(scip,  SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) <= SCIPadjustedVarUb(scip, cand, candbrpoint) )
         deltaminus = 0.0;
      else
         deltaminus = SCIPgetSolVal(scip, NULL, cand) - SCIPadjustedVarUb(scip, cand, candbrpoint);
      if( SCIPisInfinity(scip, -SCIPgetSolVal(scip, NULL, cand)) || SCIPgetSolVal(scip, NULL, cand) >= SCIPadjustedVarLb(scip, cand, candbrpoint) )
         deltaplus = 0.0;
      else
         deltaplus = SCIPadjustedVarLb(scip, cand, candbrpoint) - SCIPgetSolVal(scip, NULL, cand);
      break;

   case 'd':
      if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) )
         deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum);
      else
         deltaminus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand);

      if( SCIPisInfinity(scip,  SCIPvarGetUbLocal(cand)) )
         deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum);
      else
         deltaplus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint);
      break;
      
   case 's':
      if( SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand)) )
         deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum);
      else
         deltaplus = SCIPadjustedVarUb(scip, cand, candbrpoint) - SCIPvarGetLbLocal(cand);

      if( SCIPisInfinity(scip,  SCIPvarGetUbLocal(cand)) )
         deltaminus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum);
      else
         deltaminus = SCIPvarGetUbLocal(cand) - SCIPadjustedVarLb(scip, cand, candbrpoint);
      break;

   case 'v':
      deltaplus = SCIPisInfinity(scip, candscoremax) ? SCIPinfinity(scip) : WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum);
      deltaminus = deltaplus;
      break;

   default :
      SCIPerrorMessage("branching strategy %c unknown\n", strategy);
      SCIPABORT();
      return SCIP_INVALIDDATA;  /*lint !e527*/
   }

   if( SCIPisInfinity(scip, deltaminus) || SCIPisInfinity(scip, deltaplus) )
   {
      branchscore = SCIPinfinity(scip);
   }
   else
   {
      pscostdown  = SCIPgetVarPseudocostVal(scip, cand, -deltaminus);
      pscostup    = SCIPgetVarPseudocostVal(scip, cand,  deltaplus);
      branchscore = SCIPgetBranchScore(scip, cand, pscostdown, pscostup);
      assert(!SCIPisNegative(scip, branchscore));
   }
   SCIPdebugMessage("branching score variable <%s>[%g,%g] = %g; wscore = %g; type=%d bestbrscore=%g\n",
      SCIPvarGetName(cand), SCIPvarGetLbLocal(cand), SCIPvarGetUbLocal(cand), branchscore, WEIGHTEDSCORING(branchruledata, candscoremin, candscoremax, candscoresum),
      SCIPvarGetType(cand), *bestscore);

   if( SCIPisInfinity(scip, branchscore) )
      branchscore = 0.9*SCIPinfinity(scip);
   
   if( SCIPisSumGT(scip, branchscore, *bestscore) )
   {
      (*bestscore)   = branchscore;
      (*bestvar)     = cand;
      (*bestbrpoint) = candbrpoint;
   }
   else if( SCIPisSumEQ(scip, branchscore, *bestscore)
      && !(SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) && SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) )
   {
      /* if best candidate so far is not unbounded to both sides, maybe take new candidate */
      if( (SCIPisInfinity(scip, -SCIPvarGetLbLocal(cand))     || SCIPisInfinity(scip, SCIPvarGetUbLocal(cand))) &&
          (SCIPisInfinity(scip, -SCIPvarGetLbLocal(*bestvar)) || SCIPisInfinity(scip, SCIPvarGetUbLocal(*bestvar))) )
      { 
         /* if both variables are unbounded but one of them is bounded on one side, take the one with the larger bound on this side (hope that this avoids branching on always the same variable) */
         if( SCIPvarGetUbLocal(cand) > SCIPvarGetUbLocal(*bestvar) || SCIPvarGetLbLocal(cand) < SCIPvarGetLbLocal(*bestvar) )
         {
            (*bestscore)   = branchscore;
            (*bestvar)     = cand;
            (*bestbrpoint) = candbrpoint;
         }
      }
      else if( SCIPvarGetType(*bestvar) == SCIPvarGetType(cand) )
      { 
         /* if both have the same type, take the one with larger diameter */
         if( SCIPvarGetUbLocal(*bestvar) - SCIPvarGetLbLocal(*bestvar) < SCIPvarGetUbLocal(cand) - SCIPvarGetLbLocal(cand) )
         {
            (*bestscore)   = branchscore;
            (*bestvar)     = cand;
            (*bestbrpoint) = candbrpoint;
         }
      }
      else if( SCIPvarGetType(*bestvar) > SCIPvarGetType(cand) )
      { 
         /* take the one with better type ("more discrete") */
         (*bestscore)   = branchscore;
         (*bestvar)     = cand;
         (*bestbrpoint) = candbrpoint;
      }
   }

   return SCIP_OKAY;
}
示例#2
0
/** branching execution method for external candidates */
static
SCIP_DECL_BRANCHEXECEXT(branchExecextPscost)
{  /*lint --e{715}*/
   SCIP_BRANCHRULEDATA* branchruledata;
   SCIP_VAR** externcands;
   SCIP_Real* externcandssol;
   SCIP_Real* externcandsscore;
   int nprioexterncands;
   SCIP_VAR* brvar;
   SCIP_Real brpoint;
   int nchildren;

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

   SCIPdebugMessage("Execext method of pscost branching\n");
   
   /* get branching candidates */
   SCIP_CALL( SCIPgetExternBranchCands(scip, &externcands, &externcandssol, &externcandsscore, NULL, &nprioexterncands, NULL, NULL, NULL) );
   assert(nprioexterncands > 0);
   
   /* get current update strategy for pseudo costs, if our multiplier rule is 'u' */
   if( branchruledata->strategy == 'u' )
   {
      SCIP_CALL( SCIPgetCharParam(scip, "branching/lpgainnormalize", &branchruledata->updatestrategy) );
   }

   /* select branching variable */
   SCIP_CALL( selectBranchVar(scip, branchrule, externcands, externcandssol, externcandsscore, nprioexterncands, &brvar, &brpoint) );
   
   if( brvar == NULL )
   {
      SCIPerrorMessage("branchExecextPscost failed to select a branching variable from %d candidates\n", nprioexterncands);
      *result = SCIP_DIDNOTRUN;
      return SCIP_OKAY;
   }
  
   assert(SCIPvarIsActive(SCIPvarGetProbvar(brvar)));

   SCIPdebugMessage("branching on variable <%s>: new intervals: [%g, %g] and [%g, %g]\n",
      SCIPvarGetName(brvar), SCIPvarGetLbLocal(brvar), SCIPadjustedVarUb(scip, brvar, brpoint), SCIPadjustedVarLb(scip, brvar, brpoint), SCIPvarGetUbLocal(brvar));

   if( branchruledata->nchildren > 2 && SCIPnodeGetDepth(SCIPgetCurrentNode(scip)) <= branchruledata->narymaxdepth )
   {
      /* do n-ary branching */
      SCIP_Real minwidth;

      minwidth = 0.0;
      if( !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(brvar)) && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(brvar)) )
         minwidth = branchruledata->naryminwidth * (SCIPvarGetUbGlobal(brvar) - SCIPvarGetLbGlobal(brvar));

      SCIP_CALL( SCIPbranchVarValNary(scip, brvar, brpoint, branchruledata->nchildren, minwidth, branchruledata->narywidthfactor, &nchildren) );
   }
   else
   {
      /* do binary branching */
      SCIP_CALL( SCIPbranchVarValNary(scip, brvar, brpoint, 2, 0.0, 1.0, &nchildren) );
   }

   if( nchildren > 1 )
   {
      *result = SCIP_BRANCHED;
   }
   else
   {
      /* if there are no children, then variable should have been fixed by SCIPbranchVarVal */
      assert(SCIPisEQ(scip, SCIPvarGetLbLocal(brvar), SCIPvarGetUbLocal(brvar)));
      *result = SCIP_REDUCEDDOM;
   }

   return SCIP_OKAY;
}
示例#3
0
/** compares the so far best branching candidate with a new candidate and updates best candidate, if new candidate is better */
static
void updateBestCandidate(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_VAR**            bestvar,            /**< best branching candidate */
   SCIP_Real*            bestscore,          /**< score of best branching candidate */
   SCIP_Real*            bestobj,            /**< absolute objective value of best branching candidate */
   SCIP_Real*            bestsol,            /**< proposed branching point of best branching candidate */
   SCIP_VAR*             cand,               /**< branching candidate to consider */
   SCIP_Real             candscore,          /**< scoring of branching candidate */
   SCIP_Real             candsol             /**< proposed branching point of branching candidate */
   )
{
   SCIP_Real obj;

   assert(scip != NULL);
   assert(bestvar != NULL);
   assert(bestscore != NULL);
   assert(bestobj != NULL);
   assert(*bestobj >= 0.0);
   assert(cand != NULL);

   /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */
   assert(SCIPvarIsActive(SCIPvarGetProbvar(cand)) ||
      SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR);

   if( SCIPvarGetStatus(SCIPvarGetProbvar(cand)) == SCIP_VARSTATUS_MULTAGGR )
   {
      /* for a multi-aggregated variable, we call updateBestCandidate function recursively with all variables in the multi-aggregation */
      SCIP_VAR** multvars;
      int nmultvars;
      int i;
      SCIP_Bool success;
      SCIP_Real multvarlb;
      SCIP_Real multvarub;

      cand = SCIPvarGetProbvar(cand);
      multvars = SCIPvarGetMultaggrVars(cand);
      nmultvars = SCIPvarGetMultaggrNVars(cand);

      /* if we have a candidate branching point, then first register only aggregation variables
       * for which we can compute a corresponding branching point too (see also comments below)
       * if this fails, then register all (unfixed) aggregation variables, thereby forgetting about candsol
       */
      success = FALSE;
      if( candsol != SCIP_INVALID ) /*lint !e777*/
      {
         SCIP_Real* multscalars;
         SCIP_Real minact;
         SCIP_Real maxact;
         SCIP_Real aggrvarsol;
         SCIP_Real aggrvarsol1;
         SCIP_Real aggrvarsol2;

         multscalars = SCIPvarGetMultaggrScalars(cand);

         /* for computing the branching point, we need the current bounds of the multi-aggregated variable */
         minact = SCIPcomputeVarLbLocal(scip, cand);
         maxact = SCIPcomputeVarUbLocal(scip, cand);

         for( i = 0; i < nmultvars; ++i )
         {
            /* skip fixed variables */
            multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
            multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
            if( SCIPisEQ(scip, multvarlb, multvarub) )
               continue;

            assert(multscalars != NULL);
            assert(multscalars[i] != 0.0);

            /* we cannot ensure that both the upper bound in the left node and the lower bound in the right node
             * will be candsol by a clever choice for the branching point of multvars[i],
             * but we can try to ensure that at least one of them will be at candsol
             */
            if( multscalars[i] > 0.0 )
            {
               /*    cand >= candsol
                * if multvars[i] >= (candsol - (maxact - multscalars[i] * ub(multvars[i]))) / multscalars[i]
                *                 = (candsol - maxact) / multscalars[i] + ub(multvars[i])
                */
               aggrvarsol1 = (candsol - maxact) / multscalars[i] + multvarub;

               /*     cand <= candsol
                * if multvars[i] <= (candsol - (minact - multscalar[i] * lb(multvars[i]))) / multscalars[i]
                *                 = (candsol - minact) / multscalars[i] + lb(multvars[i])
                */
               aggrvarsol2 = (candsol - minact) / multscalars[i] + multvarlb;
            }
            else
            {
               /*    cand >= candsol
                * if multvars[i] <= (candsol - (maxact - multscalars[i] * lb(multvars[i]))) / multscalars[i]
                *                 = (candsol - maxact) / multscalars[i] + lb(multvars[i])
                */
               aggrvarsol2 = (candsol - maxact) / multscalars[i] + multvarlb;

               /*    cand <= candsol
                * if multvars[i] >= (candsol - (minact - multscalar[i] * ub(multvars[i]))) / multscalars[i]
                *                 = (candsol - minact) / multscalars[i] + ub(multvars[i])
                */
               aggrvarsol1 = (candsol - minact) / multscalars[i] + multvarub;
            }

            /* by the above choice, aggrvarsol1 <= ub(multvars[i]) and aggrvarsol2 >= lb(multvars[i])
             * if aggrvarsol1 <= lb(multvars[i]) or aggrvarsol2 >= ub(multvars[i]), then choose the other one
             * if both are out of bounds, then give up
             * if both are inside bounds, then choose the one closer to 0.0 (someone has better idea???)
             */
            if( SCIPisFeasLE(scip, aggrvarsol1, multvarlb) )
            {
               if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
                  continue;
               else
                  aggrvarsol = aggrvarsol2;
            }
            else
            {
               if( SCIPisFeasGE(scip, aggrvarsol2, multvarub) )
                  aggrvarsol = aggrvarsol1;
               else
                  aggrvarsol = REALABS(aggrvarsol1) < REALABS(aggrvarsol2) ? aggrvarsol1 : aggrvarsol2;
            }
            success = TRUE;

            updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
                  multvars[i], candscore, aggrvarsol);
         }
      }

      if( !success )
         for( i = 0; i < nmultvars; ++i )
         {
            /* skip fixed variables */
            multvarlb = SCIPcomputeVarLbLocal(scip, multvars[i]);
            multvarub = SCIPcomputeVarUbLocal(scip, multvars[i]);
            if( SCIPisEQ(scip, multvarlb, multvarub) )
               continue;

            updateBestCandidate(scip, bestvar, bestscore, bestobj, bestsol,
               multvars[i], candscore, SCIP_INVALID);
         }

      assert(*bestvar != NULL); /* if all variables were fixed, something is strange */

      return;
   }

   candscore *= SCIPvarGetBranchFactor(cand);
   obj = SCIPvarGetObj(cand);
   obj = REALABS(obj);
   if( SCIPisInfinity(scip, *bestscore)
      || (!SCIPisInfinity(scip, candscore) && 
          (SCIPisLT(scip, candscore, *bestscore) || (SCIPisLE(scip, candscore, *bestscore) && obj > *bestobj))) )
   {
      *bestvar = cand;
      *bestscore = candscore;
      *bestobj = obj;
      *bestsol = candsol;
   }
}
示例#4
0
/** selects a random active variable from a given list of variables */
static
void getRandomVariable(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_VAR**            cands,              /**< array of branching candidates */
   SCIP_Real*            candssol,           /**< relaxation solution values of branching candidates, or NULL */
   int                   ncands,             /**< number of branching candidates */
   SCIP_VAR**            bestcand,           /**< buffer to store pointer to best candidate */
   SCIP_Real*            bestcandsol,        /**< buffer to store solution value of best candidate */
   unsigned int*         seed                /**< seed for random number generator */
   )
{
   int idx;
   int firstidx;

   assert(scip != NULL);
   assert(cands != NULL);
   assert(ncands > 0);
   assert(bestcand != NULL);
   assert(bestcandsol != NULL);
   assert(seed != NULL);

   idx = SCIPgetRandomInt(0, ncands-1, seed);
   assert(idx >= 0);

   /* handle case where cands[idx] is fixed by selecting next idx with unfixed var
    * this may happen if we are inside a multi-aggregation */
   firstidx = idx;
   while( SCIPisEQ(scip, SCIPvarGetLbLocal(cands[idx]), SCIPvarGetUbLocal(cands[idx])) )
   {
      ++idx;
      if( idx == ncands )
         idx = 0;
      if( idx == firstidx )
      {
         /* odd: all variables seem to be fixed */
         SCIPdebugMessage("Warning: all branching candidates seem to be fixed\n");
         return;
      }
   }

   /* a branching variable candidate should either be an active problem variable or a multi-aggregated variable */
   assert(SCIPvarIsActive(SCIPvarGetProbvar(cands[idx])) ||
      SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR);

   if( SCIPvarGetStatus(SCIPvarGetProbvar(cands[idx])) == SCIP_VARSTATUS_MULTAGGR )
   {
      /* for a multi-aggregated variable, we call the getRandomVariable function recursively with all variables in the multi-aggregation */
      SCIP_VAR* cand;

      cand = SCIPvarGetProbvar(cands[idx]);

      getRandomVariable(scip, SCIPvarGetMultaggrVars(cand), NULL, SCIPvarGetMultaggrNVars(cand), bestcand, bestcandsol, seed);
      return;
   }

   assert(idx >= 0 && idx < ncands);

   *bestcand = cands[idx];
   assert(*bestcand != NULL);

   if( candssol != NULL )
      *bestcandsol = candssol[idx];
}
/** ensure that maxindex + 1 rows can be represented in data arrays; memory gets reallocated with 10% extra space
 *  to save some time for future allocations */
static
SCIP_RETCODE heurdataEnsureArraySize(
   SCIP*                 scip,               /**< SCIP data structure */
   SCIP_HEURDATA*        heurdata,           /**< heuristic data */
   int                   maxindex            /**< row index at hand (size must be at least this large) */
   )
{
   int newsize;
   int r;

   /* maxindex fits in current array -> nothing to do */
   if( maxindex < heurdata->memsize )
      return SCIP_OKAY;

   /* new memory size is the max index + 1 plus 10% additional space */
   newsize = (int)SCIPfeasCeil(scip, (maxindex + 1) * 1.1);
   assert(newsize > heurdata->memsize);
   assert(heurdata->memsize >= 0);

   /* alloc memory arrays for row information */
   if( heurdata->memsize == 0 )
   {
      SCIP_VAR** vars;
      int v;
      int nvars;

      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowmeans, newsize) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->rowvariances, newsize) );

      assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING);

      vars = SCIPgetVars(scip);
      nvars = SCIPgetNVars(scip);

      assert(nvars > 0);

      /* allocate variable update event processing array storage */
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varfilterposs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->varposs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->updatedvars, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentubs, nvars) );
      SCIP_CALL( SCIPallocBufferArray(scip, &heurdata->currentlbs, nvars) );

      heurdata->varpossmemsize = nvars;
      heurdata->nupdatedvars = 0;

      /* init variable event processing data */
      for( v = 0; v < nvars; ++v )
      {
         assert(SCIPvarIsActive(vars[v]));
         assert(SCIPvarGetProbindex(vars[v]) == v);

         /* set up variable events to catch bound changes */
         SCIP_CALL( SCIPcatchVarEvent(scip, vars[v], EVENT_DISTRIBUTION, heurdata->eventhdlr, NULL, &(heurdata->varfilterposs[v])) );
         assert(heurdata->varfilterposs[v] >= 0);

         heurdata->varposs[v] = -1;
         heurdata->updatedvars[v] = NULL;
         heurdata->currentlbs[v] = SCIP_INVALID;
         heurdata->currentubs[v] = SCIP_INVALID;
      }

   }
   else
   {
      SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesdown, newsize) );
      SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowinfinitiesup, newsize) );
      SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowmeans, newsize) );
      SCIP_CALL( SCIPreallocBufferArray(scip, &heurdata->rowvariances, newsize) );
   }

   /* loop over extended arrays and invalidate data to trigger initialization of this row when necessary */
   for( r = heurdata->memsize; r < newsize; ++r )
   {
      heurdata->rowmeans[r] = SCIP_INVALID;
      heurdata->rowvariances[r] = SCIP_INVALID;
      heurdata->rowinfinitiesdown[r] = 0;
      heurdata->rowinfinitiesup[r] = 0;
   }

   /* adjust memsize */
   heurdata->memsize = newsize;

   return SCIP_OKAY;
}
示例#6
0
/** LP solution separation method for disjunctive cuts */
static
SCIP_DECL_SEPAEXECLP(sepaExeclpDisjunctive)
{
   SCIP_SEPADATA* sepadata;
   SCIP_CONSHDLR* conshdlr;
   SCIP_DIGRAPH* conflictgraph;
   SCIP_ROW** rows;
   SCIP_COL** cols;
   SCIP_Real* cutcoefs = NULL;
   SCIP_Real* simplexcoefs1 = NULL;
   SCIP_Real* simplexcoefs2 = NULL;
   SCIP_Real* coef = NULL;
   SCIP_Real* binvrow = NULL;
   SCIP_Real* rowsmaxval = NULL;
   SCIP_Real* violationarray = NULL;
   int* fixings1 = NULL;
   int* fixings2 = NULL;
   int* basisind = NULL;
   int* basisrow = NULL;
   int* varrank = NULL;
   int* edgearray = NULL;
   int nedges;
   int ndisjcuts;
   int nrelevantedges;
   int nsos1vars;
   int nconss;
   int maxcuts;
   int ncalls;
   int depth;
   int ncols;
   int nrows;
   int ind;
   int j;
   int i;

   assert( sepa != NULL );
   assert( strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0 );
   assert( scip != NULL );
   assert( result != NULL );

   *result = SCIP_DIDNOTRUN;

   /* only generate disjunctive cuts if we are not close to terminating */
   if ( SCIPisStopped(scip) )
      return SCIP_OKAY;

   /* only generate disjunctive cuts if an optimal LP solution is at hand */
   if ( SCIPgetLPSolstat(scip) != SCIP_LPSOLSTAT_OPTIMAL )
      return SCIP_OKAY;

   /* only generate disjunctive cuts if the LP solution is basic */
   if ( ! SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* get LP data */
   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );

   /* return if LP has no columns or no rows */
   if ( ncols == 0 || nrows == 0 )
      return SCIP_OKAY;

   assert( cols != NULL );
   assert( rows != NULL );

   /* get sepa data */
   sepadata = SCIPsepaGetData(sepa);
   assert( sepadata != NULL );

   /* get constraint handler */
   conshdlr = sepadata->conshdlr;
   if ( conshdlr == NULL )
      return SCIP_OKAY;

   /* get number of constraints */
   nconss = SCIPconshdlrGetNConss(conshdlr);
   if ( nconss == 0 )
      return SCIP_OKAY;

   /* check for maxdepth < depth, maxinvcutsroot = 0 and maxinvcuts = 0 */
   depth = SCIPgetDepth(scip);
   if ( ( sepadata->maxdepth >= 0 && sepadata->maxdepth < depth )
      || ( depth == 0 && sepadata->maxinvcutsroot == 0 )
      || ( depth > 0 && sepadata->maxinvcuts == 0 ) )
      return SCIP_OKAY;

   /* only call the cut separator a given number of times at each node */
   ncalls = SCIPsepaGetNCallsAtNode(sepa);
   if ( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
      || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
      return SCIP_OKAY;

   /* get conflict graph and number of conflict graph edges (note that the digraph arcs were added in both directions) */
   conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
   nedges = (int)SCIPceil(scip, (SCIP_Real)SCIPdigraphGetNArcs(conflictgraph)/2);

   /* if too many conflict graph edges, the separator can be slow: delay it until no other cuts have been found */
   if ( sepadata->maxconfsdelay >= 0 && nedges >= sepadata->maxconfsdelay )
   {
      int ncutsfound;

      ncutsfound = SCIPgetNCutsFound(scip);
      if ( ncutsfound > sepadata->lastncutsfound || ! SCIPsepaWasLPDelayed(sepa) )
      {
         sepadata->lastncutsfound = ncutsfound;
         *result = SCIP_DELAYED;
         return SCIP_OKAY;
      }
   }

   /* check basis status */
   for (j = 0; j < ncols; ++j)
   {
      if ( SCIPcolGetBasisStatus(cols[j]) == SCIP_BASESTAT_ZERO )
         return SCIP_OKAY;
   }

   /* get number of SOS1 variables */
   nsos1vars = SCIPgetNSOS1Vars(conshdlr);

   /* allocate buffer arrays */
   SCIP_CALL( SCIPallocBufferArray(scip, &edgearray, nedges) );
   SCIP_CALL( SCIPallocBufferArray(scip, &fixings1, nedges) );
   SCIP_CALL( SCIPallocBufferArray(scip, &fixings2, nedges) );
   SCIP_CALL( SCIPallocBufferArray(scip, &violationarray, nedges) );

   /* get all violated conflicts {i, j} in the conflict graph and sort them based on the degree of a violation value */
   nrelevantedges = 0;
   for (j = 0; j < nsos1vars; ++j)
   {
      SCIP_VAR* var;

      var = SCIPnodeGetVarSOS1(conflictgraph, j);

      if ( SCIPvarIsActive(var) && ! SCIPisFeasZero(scip, SCIPcolGetPrimsol(SCIPvarGetCol(var))) && SCIPcolGetBasisStatus(SCIPvarGetCol(var)) == SCIP_BASESTAT_BASIC )
      {
         int* succ;
         int nsucc;

         /* get successors and number of successors */
         nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
         succ = SCIPdigraphGetSuccessors(conflictgraph, j);

         for (i = 0; i < nsucc; ++i)
         {
            SCIP_VAR* varsucc;
            int succind;

            succind = succ[i];
            varsucc = SCIPnodeGetVarSOS1(conflictgraph, succind);
            if ( SCIPvarIsActive(varsucc) && succind < j && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, varsucc) ) &&
                 SCIPcolGetBasisStatus(SCIPvarGetCol(varsucc)) == SCIP_BASESTAT_BASIC )
            {
               fixings1[nrelevantedges] = j;
               fixings2[nrelevantedges] = succind;
               edgearray[nrelevantedges] = nrelevantedges;
               violationarray[nrelevantedges++] = SCIPgetSolVal(scip, NULL, var) * SCIPgetSolVal(scip, NULL, varsucc);
            }
         }
      }
   }

   /* sort violation score values */
   if ( nrelevantedges > 0)
      SCIPsortDownRealInt(violationarray, edgearray, nrelevantedges);
   else
   {
      SCIPfreeBufferArrayNull(scip, &violationarray);
      SCIPfreeBufferArrayNull(scip, &fixings2);
      SCIPfreeBufferArrayNull(scip, &fixings1);
      SCIPfreeBufferArrayNull(scip, &edgearray);

      return SCIP_OKAY;
   }
   SCIPfreeBufferArrayNull(scip, &violationarray);

   /* compute maximal number of cuts */
   if ( SCIPgetDepth(scip) == 0 )
      maxcuts = MIN(sepadata->maxinvcutsroot, nrelevantedges);
   else
      maxcuts = MIN(sepadata->maxinvcuts, nrelevantedges);
   assert( maxcuts > 0 );

   /* allocate buffer arrays */
   SCIP_CALL( SCIPallocBufferArray(scip, &varrank, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &rowsmaxval, nrows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &basisrow, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &coef, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &simplexcoefs1, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &simplexcoefs2, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, ncols) );
   SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );

   /* get basis indices */
   SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );

   /* create vector "basisrow" with basisrow[column of non-slack basis variable] = corresponding row of B^-1;
    * compute maximum absolute value of nonbasic row coefficients */
   for (j = 0; j < nrows; ++j)
   {
      SCIP_COL** rowcols;
      SCIP_Real* rowvals;
      SCIP_ROW* row;
      SCIP_Real val;
      SCIP_Real max = 0.0;
      int nnonz;

      /* fill basisrow vector */
      ind = basisind[j];
      if ( ind >= 0 )
         basisrow[ind] = j;

      /* compute maximum absolute value of nonbasic row coefficients */
      row = rows[j];
      assert( row != NULL );
      rowvals = SCIProwGetVals(row);
      nnonz = SCIProwGetNNonz(row);
      rowcols = SCIProwGetCols(row);

      for (i = 0; i < nnonz; ++i)
      {
         if ( SCIPcolGetBasisStatus(rowcols[i]) == SCIP_BASESTAT_LOWER  || SCIPcolGetBasisStatus(rowcols[i]) == SCIP_BASESTAT_UPPER )
         {
            val = REALABS(rowvals[i]);
            if ( SCIPisFeasGT(scip, val, max) )
               max = REALABS(val);
         }
      }

      /* handle slack variable coefficient and save maximum value */
      rowsmaxval[j] = MAX(max, 1.0);
   }

   /* initialize variable ranks with -1 */
   for (j = 0; j < ncols; ++j)
      varrank[j] = -1;

   /* free buffer array */
   SCIPfreeBufferArrayNull(scip, &basisind);

   /* for the most promising disjunctions: try to generate disjunctive cuts */
   ndisjcuts = 0;
   for (i = 0; i < maxcuts; ++i)
   {
      SCIP_Bool madeintegral;
      SCIP_Real cutlhs1;
      SCIP_Real cutlhs2;
      SCIP_Real bound1;
      SCIP_Real bound2;
      SCIP_ROW* row = NULL;
      SCIP_VAR* var;
      SCIP_COL* col;

      int nonbasicnumber;
      int cutrank = 0;
      int edgenumber;
      int rownnonz;

      edgenumber = edgearray[i];

      /* determine first simplex row */
      var = SCIPnodeGetVarSOS1(conflictgraph, fixings1[edgenumber]);
      col = SCIPvarGetCol(var);
      ind = SCIPcolGetLPPos(col);
      assert( ind >= 0 );
      assert( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_BASIC );

      /* get the 'ind'th row of B^-1 and B^-1 \cdot A */
      SCIP_CALL( SCIPgetLPBInvRow(scip, basisrow[ind], binvrow, NULL, NULL) );
      SCIP_CALL( SCIPgetLPBInvARow(scip, basisrow[ind], binvrow, coef, NULL, NULL) );

      /* get the simplex-coefficients of the non-basic variables */
      SCIP_CALL( getSimplexCoefficients(scip, rows, nrows, cols, ncols, coef, binvrow, simplexcoefs1, &nonbasicnumber) );

      /* get rank of variable if not known already */
      if ( varrank[ind] < 0 )
         varrank[ind] = getVarRank(scip, binvrow, rowsmaxval, sepadata->maxweightrange, rows, nrows);
      cutrank = MAX(cutrank, varrank[ind]);

      /* get right hand side and bound of simplex talbeau row */
      cutlhs1 = SCIPcolGetPrimsol(col);
      if ( SCIPisFeasPositive(scip, cutlhs1) )
         bound1 = SCIPcolGetUb(col);
      else
         bound1 = SCIPcolGetLb(col);


      /* determine second simplex row */
      var = SCIPnodeGetVarSOS1(conflictgraph, fixings2[edgenumber]);
      col = SCIPvarGetCol(var);
      ind = SCIPcolGetLPPos(col);
      assert( ind >= 0 );
      assert( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_BASIC );

      /* get the 'ind'th row of B^-1 and B^-1 \cdot A */
      SCIP_CALL( SCIPgetLPBInvRow(scip, basisrow[ind], binvrow, NULL, NULL) );
      SCIP_CALL( SCIPgetLPBInvARow(scip, basisrow[ind], binvrow, coef, NULL, NULL) );

      /* get the simplex-coefficients of the non-basic variables */
      SCIP_CALL( getSimplexCoefficients(scip, rows, nrows, cols, ncols, coef, binvrow, simplexcoefs2, &nonbasicnumber) );

      /* get rank of variable if not known already */
      if ( varrank[ind] < 0 )
         varrank[ind] = getVarRank(scip, binvrow, rowsmaxval, sepadata->maxweightrange, rows, nrows);
      cutrank = MAX(cutrank, varrank[ind]);

      /* get right hand side and bound of simplex talbeau row */
      cutlhs2 = SCIPcolGetPrimsol(col);
      if ( SCIPisFeasPositive(scip, cutlhs2) )
         bound2 = SCIPcolGetUb(col);
      else
         bound2 = SCIPcolGetLb(col);

      /* add coefficients to cut */
      SCIP_CALL( generateDisjCutSOS1(scip, sepa, rows, nrows, cols, ncols, ndisjcuts, TRUE, sepadata->strengthen, cutlhs1, cutlhs2, bound1, bound2, simplexcoefs1, simplexcoefs2, cutcoefs, &row, &madeintegral) );
      if ( row == NULL )
         continue;

      /* raise cutrank for present cut */
      ++cutrank;

      /* check if there are numerical evidences */
      if ( ( madeintegral && ( sepadata->maxrankintegral == -1 || cutrank <= sepadata->maxrankintegral ) )
         || ( ! madeintegral && ( sepadata->maxrank == -1 || cutrank <= sepadata->maxrank ) ) )
      {
         /* possibly add cut to LP if it is useful; in case the lhs of the cut is minus infinity (due to scaling) the cut is useless */
         rownnonz = SCIProwGetNNonz(row);
         if ( rownnonz > 0 && ! SCIPisInfinity(scip, -SCIProwGetLhs(row)) && ! SCIProwIsInLP(row) && SCIPisCutEfficacious(scip, NULL, row) )
         {
            SCIP_Bool infeasible;

            /* set cut rank */
            SCIProwChgRank(row, cutrank);

            /* add cut */
            SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, &infeasible) );
            SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
            if ( infeasible )
            {
               *result = SCIP_CUTOFF;
               break;
            }
            ++ndisjcuts;
         }
      }

      /* release row */
      SCIP_CALL( SCIPreleaseRow(scip, &row) );
   }

   /* save total number of cuts found so far */
   sepadata->lastncutsfound = SCIPgetNCutsFound(scip);

   /* evaluate the result of the separation */
   if ( *result != SCIP_CUTOFF )
   {
      if ( ndisjcuts > 0 )
         *result = SCIP_SEPARATED;
      else
         *result = SCIP_DIDNOTFIND;
   }

   SCIPdebugMessage("Number of found disjunctive cuts: %d.\n", ndisjcuts);

   /* free buffer arrays */
   SCIPfreeBufferArrayNull(scip, &cutcoefs);
   SCIPfreeBufferArrayNull(scip, &simplexcoefs2);
   SCIPfreeBufferArrayNull(scip, &simplexcoefs1);
   SCIPfreeBufferArrayNull(scip, &coef);
   SCIPfreeBufferArrayNull(scip, &binvrow);
   SCIPfreeBufferArrayNull(scip, &basisrow);
   SCIPfreeBufferArrayNull(scip, &fixings2);
   SCIPfreeBufferArrayNull(scip, &fixings1);
   SCIPfreeBufferArrayNull(scip, &edgearray);
   SCIPfreeBufferArrayNull(scip, &rowsmaxval);
   SCIPfreeBufferArrayNull(scip, &varrank);

   return SCIP_OKAY;
}