예제 #1
0
/** presolving execution method */
static
SCIP_DECL_PRESOLEXEC(presolExecTrivial)
{  /*lint --e{715}*/
   SCIP_VAR** vars;
   int nvars;
   int v;

   assert(result != NULL);

   *result = SCIP_DIDNOTFIND;

   /* get the problem variables */
   vars = SCIPgetVars(scip);
   nvars = SCIPgetNVars(scip);

   /* scan the variables for trivial bound reductions
    * (loop backwards, since a variable fixing can change the current and the subsequent slots in the vars array)
    */
   for( v = nvars-1; v >= 0; --v )
   {
      SCIP_Real lb;
      SCIP_Real ub;
      SCIP_Bool infeasible;
      SCIP_Bool fixed;

      /* get variable's bounds */
      lb = SCIPvarGetLbGlobal(vars[v]);
      ub = SCIPvarGetUbGlobal(vars[v]);

      /* is variable integral? */
      if( SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS )
      {
         SCIP_Real newlb;
         SCIP_Real newub;
         
         /* round fractional bounds on integer variables */
         newlb = SCIPfeasCeil(scip, lb);
         newub = SCIPfeasFloor(scip, ub);

         /* check bounds on variable for infeasibility */
         if( newlb > newub + 0.5 )
         {
            SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL,
               "problem infeasible: integral variable <%s> has bounds [%.17f,%.17f] rounded to [%.17f,%.17f]\n",
               SCIPvarGetName(vars[v]), lb, ub, newlb, newub);
            *result = SCIP_CUTOFF;
            return SCIP_OKAY;
         }

         /* fix variables with equal bounds */
         if( newlb > newub - 0.5 )
         {
            SCIPdebugMessage("fixing integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n",
               SCIPvarGetName(vars[v]), lb, ub, newlb, newub);
            SCIP_CALL( SCIPfixVar(scip, vars[v], newlb, &infeasible, &fixed) );
            if( infeasible )
            {
               SCIPdebugMessage(" -> infeasible fixing\n");
               *result = SCIP_CUTOFF;
               return SCIP_OKAY;
            }
            assert(fixed);
            (*nfixedvars)++;
         }
         else
         {
            /* round fractional bounds */
            if( !SCIPisFeasEQ(scip, lb, newlb) )
            {
               SCIPdebugMessage("rounding lower bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n",
                  SCIPvarGetName(vars[v]), lb, ub, newlb, ub);
               SCIP_CALL( SCIPchgVarLb(scip, vars[v], newlb) );
               (*nchgbds)++;
            }
            if( !SCIPisFeasEQ(scip, ub, newub) )
            {
               SCIPdebugMessage("rounding upper bound of integral variable <%s>: [%.17f,%.17f] -> [%.17f,%.17f]\n",
                  SCIPvarGetName(vars[v]), newlb, ub, newlb, newub);
               SCIP_CALL( SCIPchgVarUb(scip, vars[v], newub) );
               (*nchgbds)++;
            }
         }
      }
      else
      {
         /* check bounds on continuous variable for infeasibility */
         if( SCIPisFeasGT(scip, lb, ub) )
         {
            SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL,
               "problem infeasible: continuous variable <%s> has bounds [%.17f,%.17f]\n",
               SCIPvarGetName(vars[v]), lb, ub);
            *result = SCIP_CUTOFF;
            return SCIP_OKAY;
         }

         /* fix variables with equal bounds */
         if( SCIPisEQ(scip, lb, ub) )
         {
            SCIP_Real fixval;

#ifdef FIXSIMPLEVALUE
            fixval = SCIPselectSimpleValue(lb - 0.9 * SCIPepsilon(scip), ub + 0.9 * SCIPepsilon(scip), MAXDNOM);
#else
            fixval = (lb + ub)/2;
#endif
            SCIPdebugMessage("fixing continuous variable <%s>[%.17f,%.17f] to %.17f\n", 
               SCIPvarGetName(vars[v]), lb, ub, fixval);
            SCIP_CALL( SCIPfixVar(scip, vars[v], fixval, &infeasible, &fixed) );
            if( infeasible )
            {
               SCIPdebugMessage(" -> infeasible fixing\n");
               *result = SCIP_CUTOFF;
               return SCIP_OKAY;
            }
            assert(fixed);
            (*nfixedvars)++;
         }
      }
   }

   return SCIP_OKAY;
}
예제 #2
0
/** computes a disjunctive cut inequality based on two simplex taubleau rows */
static
SCIP_RETCODE generateDisjCutSOS1(
   SCIP*                 scip,               /**< SCIP pointer */
   SCIP_SEPA*            sepa,               /**< separator */
   SCIP_ROW**            rows,               /**< LP rows */
   int                   nrows,              /**< number of LP rows */
   SCIP_COL**            cols,               /**< LP columns */
   int                   ncols,              /**< number of LP columns */
   int                   ndisjcuts,          /**< number of disjunctive cuts found so far */
   SCIP_Bool             scale,              /**< should cut be scaled */
   SCIP_Bool             strengthen,         /**< should cut be strengthened if integer variables are present */
   SCIP_Real             cutlhs1,            /**< left hand side of the first simplex row */
   SCIP_Real             cutlhs2,            /**< left hand side of the second simplex row */
   SCIP_Real             bound1,             /**< bound of first simplex row */
   SCIP_Real             bound2,             /**< bound of second simplex row */
   SCIP_Real*            simplexcoefs1,      /**< simplex coefficients of first row */
   SCIP_Real*            simplexcoefs2,      /**< simplex coefficients of second row */
   SCIP_Real*            cutcoefs,           /**< pointer to store cut coefficients (length: nscipvars) */
   SCIP_ROW**            row,                /**< pointer to store disjunctive cut inequality */
   SCIP_Bool*            madeintegral        /**< pointer to store whether cut has been scaled to integral values */
   )
{
   char cutname[SCIP_MAXSTRLEN];
   SCIP_COL** rowcols;
   SCIP_COL* col;
   SCIP_Real* rowvals;
   SCIP_Real lhsrow;
   SCIP_Real rhsrow;
   SCIP_Real cutlhs;
   SCIP_Real sgn;
   SCIP_Real lb;
   SCIP_Real ub;
   int nonbasicnumber = 0;
   int rownnonz;
   int ind;
   int r;
   int c;

   assert( scip != NULL );
   assert( row != NULL );
   assert( rows != NULL );
   assert( cols != NULL );
   assert( simplexcoefs1 != NULL );
   assert( simplexcoefs2 != NULL );
   assert( cutcoefs != NULL );
   assert( sepa != NULL );
   assert( madeintegral != NULL );

   *madeintegral = FALSE;

   /* check signs */
   if ( SCIPisFeasPositive(scip, cutlhs1) == SCIPisFeasPositive(scip, cutlhs2) )
      sgn = 1.0;
   else
      sgn = -1.0;

   /* check bounds */
   if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) )
      strengthen = FALSE;

   /* compute left hand side of row (a later update is possible, see below) */
   cutlhs = sgn * cutlhs1 * cutlhs2;

   /* add cut-coefficients of the non-basic non-slack variables */
   for (c = 0; c < ncols; ++c)
   {
      col = cols[c];
      assert( col != NULL );
      ind = SCIPcolGetLPPos(col);
      assert( ind >= 0 );

      if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_LOWER )
      {
         lb = SCIPcolGetLb(col);

         /* for integer variables we may obtain stronger coefficients */
         if ( strengthen && SCIPcolIsIntegral(col) )
         {
            SCIP_Real mval;
            SCIP_Real mvalfloor;
            SCIP_Real mvalceil;

            mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2);
            mvalfloor = SCIPfloor(scip, mval);
            mvalceil = SCIPceil(scip, mval);

            cutcoefs[ind] = MIN(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] - mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] + mvalceil * bound2));
            assert( SCIPisFeasLE(scip, cutcoefs[ind], MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) );
         }
         else
            cutcoefs[ind] = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]);

         cutlhs += cutcoefs[ind] * lb;
         ++nonbasicnumber;
      }
      else if ( SCIPcolGetBasisStatus(col) == SCIP_BASESTAT_UPPER )
      {
         ub = SCIPcolGetUb(col);

         /* for integer variables we may obtain stronger coefficients */
         if ( strengthen && SCIPcolIsIntegral(col) )
         {
            SCIP_Real mval;
            SCIP_Real mvalfloor;
            SCIP_Real mvalceil;

            mval = (cutlhs2 * simplexcoefs1[nonbasicnumber] - cutlhs1 * simplexcoefs2[nonbasicnumber]) / (cutlhs2 * bound1 + cutlhs1 * bound2);
            mvalfloor = SCIPfloor(scip, -mval);
            mvalceil = SCIPceil(scip, -mval);

            cutcoefs[ind] = MAX(sgn * cutlhs2 * (simplexcoefs1[nonbasicnumber] + mvalfloor * bound1), sgn * cutlhs1 * (simplexcoefs2[nonbasicnumber] - mvalceil * bound2));
            assert( SCIPisFeasLE(scip, -cutcoefs[ind], -MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber])) );
         }
         else
            cutcoefs[ind] = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]);

         cutlhs += cutcoefs[ind] * ub;
         ++nonbasicnumber;
      }
      else
      {
         assert( SCIPcolGetBasisStatus(col) != SCIP_BASESTAT_ZERO );
         cutcoefs[ind] = 0.0;
      }
   }

   /* add cut-coefficients of the non-basic slack variables */
   for (r = 0; r < nrows; ++r)
   {
      rhsrow = SCIProwGetRhs(rows[r]) - SCIProwGetConstant(rows[r]);
      lhsrow = SCIProwGetLhs(rows[r]) - SCIProwGetConstant(rows[r]);

      assert( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_ZERO );
      assert( SCIPisFeasZero(scip, lhsrow - rhsrow) || SCIPisNegative(scip, lhsrow - rhsrow) );
      assert( SCIProwIsInLP(rows[r]) );

      if ( SCIProwGetBasisStatus(rows[r]) != SCIP_BASESTAT_BASIC )
      {
         SCIP_Real cutcoef;

         if ( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_UPPER )
         {
            assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetRhs(rows[r])) );

            cutcoef = MAX(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]);
            cutlhs -= cutcoef * rhsrow;
            ++nonbasicnumber;
         }
         else /* SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER */
         {
            assert( SCIProwGetBasisStatus(rows[r]) == SCIP_BASESTAT_LOWER );
            assert( SCIPisFeasZero(scip, SCIPgetRowLPActivity(scip, rows[r]) - SCIProwGetLhs(rows[r])) );

            cutcoef = MIN(sgn * cutlhs2 * simplexcoefs1[nonbasicnumber], sgn * cutlhs1 * simplexcoefs2[nonbasicnumber]);
            cutlhs -= cutcoef * lhsrow;
            ++nonbasicnumber;
         }

         rownnonz = SCIProwGetNNonz(rows[r]);
         rowvals = SCIProwGetVals(rows[r]);
         rowcols = SCIProwGetCols(rows[r]);

         for (c = 0; c < rownnonz; ++c)
         {
            ind = SCIPcolGetLPPos(rowcols[c]);

            /* if column is not in LP, then return without generating cut */
            if ( ind < 0 )
            {
               *row = NULL;
               return SCIP_OKAY;
            }

            cutcoefs[ind] -= cutcoef * rowvals[c];
         }
      }
   }

   /* create cut */
   (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_%d_%d", SCIPsepaGetName(sepa), SCIPgetNLPs(scip), ndisjcuts);
   if ( SCIPgetDepth(scip) == 0 )
      SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
   else
      SCIP_CALL( SCIPcreateEmptyRowSepa(scip, row, sepa, cutname, cutlhs, SCIPinfinity(scip), TRUE, FALSE, TRUE) );

   SCIP_CALL( SCIPcacheRowExtensions(scip, *row) );
   for (c = 0; c < ncols; ++c)
   {
      ind = SCIPcolGetLPPos(cols[c]);
      assert( ind >= 0 );
      if ( ! SCIPisFeasZero(scip, cutcoefs[ind]) )
      {
         SCIP_CALL( SCIPaddVarToRow(scip, *row, SCIPcolGetVar(cols[c]), cutcoefs[ind] ) );
      }
   }
   SCIP_CALL( SCIPflushRowExtensions(scip, *row) );

   /* try to scale the cut to integral values
    * @todo find better but still stable disjunctive cut settings
    */
   if ( scale )
   {
      int maxdepth;
      int depth;
      SCIP_Longint maxdnom;
      SCIP_Real maxscale;

      depth = SCIPgetDepth(scip);
      assert( depth >= 0 );
      maxdepth = SCIPgetMaxDepth(scip);
      if ( depth == 0 )
      {
         maxdnom = 1000;
         maxscale = 1000.0;
      }
      else if ( depth <= maxdepth/4 )
      {
         maxdnom = 1000;
         maxscale = 1000.0;
      }
      else if ( depth <= maxdepth/2 )
      {
         maxdnom = 100;
         maxscale = 100.0;
      }
      else
      {
         maxdnom = 10;
         maxscale = 10.0;
      }

      SCIP_CALL( SCIPmakeRowIntegral(scip, *row, -SCIPepsilon(scip), SCIPsumepsilon(scip), maxdnom, maxscale, TRUE, madeintegral) );
   }

   return SCIP_OKAY;
}
예제 #3
0
/** LP solution separation method of separator */
static
SCIP_DECL_SEPAEXECLP(sepaExeclpGomory)
{  /*lint --e{715}*/
   SCIP_SEPADATA* sepadata;
   SCIP_VAR** vars;
   SCIP_COL** cols;
   SCIP_ROW** rows;
   SCIP_Real* binvrow;
   SCIP_Real* cutcoefs;
   SCIP_Real maxscale;
   SCIP_Real minfrac;
   SCIP_Real maxfrac;
   SCIP_Longint maxdnom;
   SCIP_Bool cutoff;
   int* basisind;
   int naddedcuts;
   int nvars;
   int ncols;
   int nrows;
   int ncalls;
   int depth;
   int maxdepth;
   int maxsepacuts;
   int c;
   int i;

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

   *result = SCIP_DIDNOTRUN;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   depth = SCIPgetDepth(scip);
   ncalls = SCIPsepaGetNCallsAtNode(sepa);

   minfrac = sepadata->away;
   maxfrac = 1.0 - sepadata->away;

   /* only call separator, if we are not close to terminating */
   if( SCIPisStopped(scip) )
      return SCIP_OKAY;

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

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

   /* only call separator, if the LP solution is basic */
   if( !SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* only call separator, if there are fractional variables */
   if( SCIPgetNLPBranchCands(scip) == 0 )
      return SCIP_OKAY;

   /* get variables data */
   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );

   /* get LP data */
   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
   if( ncols == 0 || nrows == 0 )
      return SCIP_OKAY;

#if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */
   if( ncols >= 50*nrows )
      return SCIP_OKAY;

   if( ncols >= 5*nrows )
   {
      int ncutsfound;

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

   /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to
    * scale resulting cut to integral values to avoid numerical instabilities
    */
   /**@todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */
   maxdepth = SCIPgetMaxDepth(scip);
   if( depth == 0 )
   {
      maxdnom = 1000;
      maxscale = 1000.0;
   }
   else if( depth <= maxdepth/4 )
   {
      maxdnom = 1000;
      maxscale = 1000.0;
   }
   else if( depth <= maxdepth/2 )
   {
      maxdnom = 100;
      maxscale = 100.0;
   }
   else
   {
      maxdnom = 10;
      maxscale = 10.0;
   }

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );

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

   /* get the maximal number of cuts allowed in a separation round */
   if( depth == 0 )
      maxsepacuts = sepadata->maxsepacutsroot;
   else
      maxsepacuts = sepadata->maxsepacuts;

   SCIPdebugMessage("searching gomory cuts: %d cols, %d rows, maxdnom=%"SCIP_LONGINT_FORMAT", maxscale=%g, maxcuts=%d\n",
      ncols, nrows, maxdnom, maxscale, maxsepacuts);

   cutoff = FALSE;
   naddedcuts = 0;

   /* for all basic columns belonging to integer variables, try to generate a gomory cut */
   for( i = 0; i < nrows && naddedcuts < maxsepacuts && !SCIPisStopped(scip) && !cutoff; ++i )
   {
      SCIP_Bool tryrow;

      tryrow = FALSE;
      c = basisind[i];
      if( c >= 0 )
      {
         SCIP_VAR* var;

         assert(c < ncols);
         var = SCIPcolGetVar(cols[c]);
         if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
         {
            SCIP_Real primsol;

            primsol = SCIPcolGetPrimsol(cols[c]);
            assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/

            if( SCIPfeasFrac(scip, primsol) >= minfrac )
            {
               SCIPdebugMessage("trying gomory cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol);
               tryrow = TRUE;
            }
         }
      }
      else if( sepadata->separaterows )
      {
         SCIP_ROW* row;

         assert(0 <= -c-1 && -c-1 < nrows);
         row = rows[-c-1];
         if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
         {
            SCIP_Real primsol;

            primsol = SCIPgetRowActivity(scip, row);
            if( SCIPfeasFrac(scip, primsol) >= minfrac )
            {
               SCIPdebugMessage("trying gomory cut for row <%s> [%g]\n", SCIProwGetName(row), primsol);
               tryrow = TRUE;
            }
         }
      }

      if( tryrow )
      {
         SCIP_Real cutrhs;
         SCIP_Real cutact;
         SCIP_Bool success;
         SCIP_Bool cutislocal;

         /* get the row of B^-1 for this basic integer variable with fractional solution value */
         SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow) );

         cutact = 0.0;
         cutrhs = SCIPinfinity(scip);

         /* create a MIR cut out of the weighted LP rows using the B^-1 row as weights */
         SCIP_CALL( SCIPcalcMIR(scip, NULL, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, FIXINTEGRALRHS, NULL, NULL,
               (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, minfrac, maxfrac,
               binvrow, 1.0, NULL, NULL, cutcoefs, &cutrhs, &cutact, &success, &cutislocal) );
         assert(ALLOWLOCAL || !cutislocal);

         /* @todo Currently we are using the SCIPcalcMIR() function to compute the coefficients of the Gomory
          *       cut. Alternatively, we could use the direct version (see thesis of Achterberg formula (8.4)) which
          *       leads to cut a of the form \sum a_i x_i \geq 1. Rumor has it that these cuts are better.
          */

         SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs);

         /* if successful, convert dense cut into sparse row, and add the row as a cut */
         if( success && SCIPisFeasGT(scip, cutact, cutrhs) )
         {
            SCIP_ROW* cut;
            char cutname[SCIP_MAXSTRLEN];
            int v;

            /* construct cut name */
            if( c >= 0 )
               (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_x%d", SCIPgetNLPs(scip), c);
            else
               (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "gom%d_s%d", SCIPgetNLPs(scip), -c-1);

            /* create empty cut */
            SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs,
                  cutislocal, FALSE, sepadata->dynamiccuts) );

            /* cache the row extension and only flush them if the cut gets added */
            SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );

            /* collect all non-zero coefficients */
            for( v = 0; v < nvars; ++v )
            {
               if( !SCIPisZero(scip, cutcoefs[v]) )
               {
                  SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[v], cutcoefs[v]) );
               }
            }

            if( SCIProwGetNNonz(cut) == 0 )
            {
               assert(SCIPisFeasNegative(scip, cutrhs));
               SCIPdebugMessage(" -> gomory cut detected infeasibility with cut 0 <= %f\n", cutrhs);
               cutoff = TRUE;
            }
            else if( SCIProwGetNNonz(cut) == 1 )
            {
               /* add the bound change as cut to avoid that the LP gets modified. that would mean the LP is not flushed
                * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply that bound change automatically
                */
               SCIP_CALL( SCIPaddCut(scip, NULL, cut, TRUE) );
               naddedcuts++;
            }
            else
            {
               /* Only take efficacious cuts, except for cuts with one non-zero coefficients (= bound
                * changes); the latter cuts will be handeled internally in sepastore.
                */
               if( SCIPisCutEfficacious(scip, NULL, cut) )
               {
                  assert(success == TRUE);

                  SCIPdebugMessage(" -> gomory cut for <%s>: act=%f, rhs=%f, eff=%f\n",
                     c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]),
                     cutact, cutrhs, SCIPgetCutEfficacy(scip, NULL, cut));

                  if( sepadata->makeintegral )
                  {
                     /* try to scale the cut to integral values */
                     SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
                           maxdnom, maxscale, MAKECONTINTEGRAL, &success) );

                     if( sepadata->forcecuts )
                        success = TRUE;

                     /* in case the left hand side in minus infinity and the right hand side is plus infinity the cut is
                      * useless so we are not taking it at all
                      */
                     if( (SCIPisInfinity(scip, -SCIProwGetLhs(cut)) && SCIPisInfinity(scip, SCIProwGetRhs(cut))) )
                        success = FALSE;

                     /* @todo Trying to make the Gomory cut integral might fail. Due to numerical reasons/arguments we
                      *       currently ignore such cuts. If the cut, however, has small support (let's say smaller or equal to
                      *       5), we might want to add that cut (even it does not have integral coefficients). To be able to
                      *       do that we need to add a rank to the data structure of a row. The rank of original rows are
                      *       zero and for aggregated rows it is the maximum over all used rows plus one.
                      */
                  }

                  if( success )
                  {
                     SCIPdebugMessage(" -> found gomory cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n",
                        cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut),
                        SCIPgetCutEfficacy(scip, NULL, cut),
                        SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut),
                        SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut));

                     /* flush all changes before adding the cut */
                     SCIP_CALL( SCIPflushRowExtensions(scip, cut) );

                     /* add global cuts which are not implicit bound changes to the cut pool */
                     if( !cutislocal )
                     {
                        if( sepadata->delayedcuts )
                        {
                           SCIP_CALL( SCIPaddDelayedPoolCut(scip, cut) );
                        }
                        else
                        {
                           SCIP_CALL( SCIPaddPoolCut(scip, cut) );
                        }
                     }
                     else
                     {
                        /* local cuts we add to the sepastore */
                        SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE) );
                     }

                     naddedcuts++;
                  }
               }
            }

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

   /* free temporary memory */
   SCIPfreeBufferArray(scip, &binvrow);
   SCIPfreeBufferArray(scip, &basisind);
   SCIPfreeBufferArray(scip, &cutcoefs);

   SCIPdebugMessage("end searching gomory cuts: found %d cuts\n", naddedcuts);

   sepadata->lastncutsfound = SCIPgetNCutsFound(scip);

   /* evalute the result of the separation */
   if( cutoff )
      *result = SCIP_CUTOFF;
   else if ( naddedcuts > 0 )
      *result = SCIP_SEPARATED;
   else
      *result = SCIP_DIDNOTFIND;

   return SCIP_OKAY;
}
예제 #4
0
/** LP solution separation method of separator */
static
SCIP_DECL_SEPAEXECLP(sepaExeclpStrongcg)
{  /*lint --e{715}*/
   SCIP_SEPADATA* sepadata;
   SCIP_VAR** vars;
   SCIP_COL** cols;
   SCIP_ROW** rows;
   SCIP_Real* varsolvals;
   SCIP_Real* binvrow;
   SCIP_Real* cutcoefs;
   SCIP_Real cutrhs;
   SCIP_Real cutact;
   SCIP_Real maxscale;
   SCIP_Longint maxdnom;
   int* basisind;
   int* inds;
   int ninds;
   int nvars;
   int ncols;
   int nrows;
   int ncalls;
   int depth;
   int maxdepth;
   int maxsepacuts;
   int ncuts;
   int c;
   int i;
   int cutrank;
   SCIP_Bool success;
   SCIP_Bool cutislocal;
   char normtype;

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

   *result = SCIP_DIDNOTRUN;

   sepadata = SCIPsepaGetData(sepa);
   assert(sepadata != NULL);

   depth = SCIPgetDepth(scip);
   ncalls = SCIPsepaGetNCallsAtNode(sepa);

   /* only call separator, if we are not close to terminating */
   if( SCIPisStopped(scip) )
      return SCIP_OKAY;

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

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

   /* only call separator, if the LP solution is basic */
   if( !SCIPisLPSolBasic(scip) )
      return SCIP_OKAY;

   /* only call separator, if there are fractional variables */
   if( SCIPgetNLPBranchCands(scip) == 0 )
      return SCIP_OKAY;

   /* get variables data */
   SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );

   /* get LP data */
   SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
   SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
   if( ncols == 0 || nrows == 0 )
      return SCIP_OKAY;

#if 0 /* if too many columns, separator is usually very slow: delay it until no other cuts have been found */
   if( ncols >= 50*nrows )
      return SCIP_OKAY;
   if( ncols >= 5*nrows )
   {
      int ncutsfound;

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

   /* get the type of norm to use for efficacy calculations */
   SCIP_CALL( SCIPgetCharParam(scip, "separating/efficacynorm", &normtype) );

   /* set the maximal denominator in rational representation of strong CG cut and the maximal scale factor to
    * scale resulting cut to integral values to avoid numerical instabilities
    */
   /**@todo find better but still stable strong CG cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */
   maxdepth = SCIPgetMaxDepth(scip);
   if( depth == 0 )
   {
      maxdnom = 1000;
      maxscale = 1000.0;
   }
   else if( depth <= maxdepth/4 )
   {
      maxdnom = 1000;
      maxscale = 1000.0;
   }
   else if( depth <= maxdepth/2 )
   {
      maxdnom = 100;
      maxscale = 100.0;
   }
   else
   {
      maxdnom = 10;
      maxscale = 10.0;
   }

   *result = SCIP_DIDNOTFIND;

   /* allocate temporary memory */
   SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
   SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
   SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) );
   varsolvals = NULL; /* allocate this later, if needed */

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

   /* get the maximal number of cuts allowed in a separation round */
   if( depth == 0 )
      maxsepacuts = sepadata->maxsepacutsroot;
   else
      maxsepacuts = sepadata->maxsepacuts;

   SCIPdebugMessage("searching strong CG cuts: %d cols, %d rows, maxdnom=%" SCIP_LONGINT_FORMAT ", maxscale=%g, maxcuts=%d\n",
      ncols, nrows, maxdnom, maxscale, maxsepacuts);

   /* for all basic columns belonging to integer variables, try to generate a strong CG cut */
   ncuts = 0;
   for( i = 0; i < nrows && ncuts < maxsepacuts && !SCIPisStopped(scip) && *result != SCIP_CUTOFF; ++i )
   {
      SCIP_Bool tryrow;

      tryrow = FALSE;
      c = basisind[i];
      if( c >= 0 )
      {
         SCIP_VAR* var;

         assert(c < ncols);
         var = SCIPcolGetVar(cols[c]);
         if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS )
         {
            SCIP_Real primsol;

            primsol = SCIPcolGetPrimsol(cols[c]);
            assert(SCIPgetVarSol(scip, var) == primsol); /*lint !e777*/

            if( SCIPfeasFrac(scip, primsol) >= MINFRAC )
            {
               SCIPdebugMessage("trying strong CG cut for col <%s> [%g]\n", SCIPvarGetName(var), primsol);
               tryrow = TRUE;
            }
         }
      }
#ifdef SEPARATEROWS
      else
      {
         SCIP_ROW* row;

         assert(0 <= -c-1 && -c-1 < nrows);
         row = rows[-c-1];
         if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
         {
            SCIP_Real primsol;

            primsol = SCIPgetRowActivity(scip, row);
            if( SCIPfeasFrac(scip, primsol) >= MINFRAC )
            {
               SCIPdebugMessage("trying strong CG cut for row <%s> [%g]\n", SCIProwGetName(row), primsol);
               tryrow = TRUE;
            }
         }
      }
#endif

      if( tryrow )
      {
         /* get the row of B^-1 for this basic integer variable with fractional solution value */
         SCIP_CALL( SCIPgetLPBInvRow(scip, i, binvrow, inds, &ninds) );

#ifdef SCIP_DEBUG
         /* initialize variables, that might not have been initialized in SCIPcalcMIR if success == FALSE */
         cutact = 0.0;
         cutrhs = SCIPinfinity(scip);
#endif
         /* create a strong CG cut out of the weighted LP rows using the B^-1 row as weights */
         SCIP_CALL( SCIPcalcStrongCG(scip, BOUNDSWITCH, USEVBDS, ALLOWLOCAL, (int) MAXAGGRLEN(nvars), sepadata->maxweightrange, MINFRAC, MAXFRAC,
               binvrow, inds, ninds, 1.0, cutcoefs, &cutrhs, &cutact, &success, &cutislocal, &cutrank) );
         assert(ALLOWLOCAL || !cutislocal);
         SCIPdebugMessage(" -> success=%u: %g <= %g\n", success, cutact, cutrhs);

         /* if successful, convert dense cut into sparse row, and add the row as a cut */
         if( success && SCIPisFeasGT(scip, cutact, cutrhs) )
         {
            SCIP_VAR** cutvars;
            SCIP_Real* cutvals;
            SCIP_Real cutnorm;
            int cutlen;

            /* if this is the first successful cut, get the LP solution for all COLUMN variables */
            if( varsolvals == NULL )
            {
               int v;

               SCIP_CALL( SCIPallocBufferArray(scip, &varsolvals, nvars) );
               for( v = 0; v < nvars; ++v )
               {
                  if( SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_COLUMN )
                     varsolvals[v] = SCIPvarGetLPSol(vars[v]);
               }
            }
            assert(varsolvals != NULL);

            /* get temporary memory for storing the cut as sparse row */
            SCIP_CALL( SCIPallocBufferArray(scip, &cutvars, nvars) );
            SCIP_CALL( SCIPallocBufferArray(scip, &cutvals, nvars) );

            /* store the cut as sparse row, calculate activity and norm of cut */
            SCIP_CALL( storeCutInArrays(scip, nvars, vars, cutcoefs, varsolvals, normtype,
                  cutvars, cutvals, &cutlen, &cutact, &cutnorm) );

            SCIPdebugMessage(" -> strong CG cut for <%s>: act=%f, rhs=%f, norm=%f, eff=%f, rank=%d\n",
               c >= 0 ? SCIPvarGetName(SCIPcolGetVar(cols[c])) : SCIProwGetName(rows[-c-1]),
               cutact, cutrhs, cutnorm, (cutact - cutrhs)/cutnorm, cutrank);

            if( SCIPisPositive(scip, cutnorm) && SCIPisEfficacious(scip, (cutact - cutrhs)/cutnorm) )
            {
               SCIP_ROW* cut;
               char cutname[SCIP_MAXSTRLEN];

               /* create the cut */
               if( c >= 0 )
                  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_x%d", SCIPgetNLPs(scip), c);
               else
                  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "scg%d_s%d", SCIPgetNLPs(scip), -c-1);
               SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, sepadata->dynamiccuts) );
               SCIP_CALL( SCIPaddVarsToRow(scip, cut, cutlen, cutvars, cutvals) );
               /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
               SCIProwChgRank(cut, cutrank);

               assert(success);
#ifdef MAKECUTINTEGRAL
               /* try to scale the cut to integral values */
               SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
                     maxdnom, maxscale, MAKECONTINTEGRAL, &success) );
#else
#ifdef MAKEINTCUTINTEGRAL
               /* try to scale the cut to integral values if there are no continuous variables
                *  -> leads to an integral slack variable that can later be used for other cuts
                */
               {
                  int k = 0;
                  while ( k < cutlen && SCIPvarIsIntegral(cutvars[k]) )
                     ++k;
                  if( k == cutlen )
                  {
                     SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
                           maxdnom, maxscale, MAKECONTINTEGRAL, &success) );
                  }
               }
#endif
#endif

#ifndef FORCECUTINTEGRAL
               success = TRUE;
#endif

               if( success )
               {
                  if( !SCIPisCutEfficacious(scip, NULL, cut) )
                  {
                     SCIPdebugMessage(" -> strong CG cut <%s> no longer efficacious: act=%f, rhs=%f, norm=%f, eff=%f\n",
                        cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut),
                        SCIPgetCutEfficacy(scip, NULL, cut));
                     /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
                     success = FALSE;
                  }
                  else
                  {
                     SCIP_Bool infeasible;

                     SCIPdebugMessage(" -> found strong CG cut <%s>: act=%f, rhs=%f, norm=%f, eff=%f, min=%f, max=%f (range=%f)\n",
                        cutname, SCIPgetRowLPActivity(scip, cut), SCIProwGetRhs(cut), SCIProwGetNorm(cut),
                        SCIPgetCutEfficacy(scip, NULL, cut),
                        SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut),
                        SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut));
                     /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
                     SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE, &infeasible) );
                     if ( infeasible )
                        *result = SCIP_CUTOFF;
                     else
                     {
                        if( !cutislocal )
                        {
                           SCIP_CALL( SCIPaddPoolCut(scip, cut) );
                        }
                        *result = SCIP_SEPARATED;
                     }
                     ncuts++;
                  }
               }
               else
               {
                  SCIPdebugMessage(" -> strong CG cut <%s> couldn't be scaled to integral coefficients: act=%f, rhs=%f, norm=%f, eff=%f\n",
                     cutname, cutact, cutrhs, cutnorm, SCIPgetCutEfficacy(scip, NULL, cut));
               }

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

            /* free temporary memory */
            SCIPfreeBufferArray(scip, &cutvals);
            SCIPfreeBufferArray(scip, &cutvars);
         }
      }
   }

   /* free temporary memory */
   SCIPfreeBufferArrayNull(scip, &varsolvals);
   SCIPfreeBufferArray(scip, &inds);
   SCIPfreeBufferArray(scip, &binvrow);
   SCIPfreeBufferArray(scip, &basisind);
   SCIPfreeBufferArray(scip, &cutcoefs);

   SCIPdebugMessage("end searching strong CG cuts: found %d cuts\n", ncuts);

   sepadata->lastncutsfound = SCIPgetNCutsFound(scip);

   return SCIP_OKAY;
}