// This chunk of code adds
// z_t = \sum_{k=1}^{2 |V_g|} \lambda_k^g, \Prod_{j \in J_t} \chi_j^{g,k}
//   \forall J_t \subseteq V_g
void
MultilinearTermsHandler::handleZDefConstraints_(RelaxationPtr relaxation, HandleCallingFunction wherefrom, ModVector &mods)
{
  for(ConstTermIterator it = termsR_.begin(); it != termsR_.end(); ++it) {
    ConstVariablePtr zt = it->first;
    SetOfVars const &jt = it->second;

    for (UInt gix = 0; gix < groups_.size(); ++gix) {
      SetOfVars &vg = groups_[gix];
       
      if (std::includes(vg.begin(), vg.end(), jt.begin(), jt.end())) { 
        // jt is a subset of vg, add constraint
        LinearFunctionPtr lf = (LinearFunctionPtr) new LinearFunction();
        lf->addTerm(zt, -1.0);
        int pix = 0;

        for (std::set<SetOfVars>::iterator it2 = points_[gix].begin(); 
             it2 != points_[gix].end(); ++it2) {
          double prodval = 1.0;
          VariablePtr lam = lambdavars_[gix][pix];

          for(SetOfVars::const_iterator jt_it = jt.begin(); jt_it != jt.end(); ++jt_it) {
            ConstVariablePtr xvar = *jt_it;
            double tmp = varIsAtLowerBoundAtPoint_(xvar, *it2) ? xvar->getLb() : xvar->getUb();
            prodval *= tmp;
          }

          lf->addTerm(lam, prodval);
          ++pix;
        }        
        FunctionPtr f = (FunctionPtr) new Function(lf);

        if (wherefrom == relaxInit_Call) {
          ConstraintPtr c = relaxation->newConstraint(f, 0.0, 0.0);
          zConMap_.insert(std::make_pair(IntVarPtrPair(gix, zt), c));
        }
        else { 
          IntVarPtrPairConstraintMap::iterator pos;
          pos = zConMap_.find(IntVarPtrPair(gix, zt));
          if (pos == zConMap_.end()) {
            assert(0);
          }
          ConstraintPtr c = pos->second;
          //XXX Here you should just check if the constraint really was going to
          //change and do nothing if it doesn't...  (will be faster).
          if (wherefrom == relaxNodeInc_Call) {
            relaxation->changeConstraint(c, lf, 0.0, 0.0);
          }
          LinConModPtr lcmod = (LinConModPtr) new LinConMod(c, lf, 0.0, 0.0); 
          mods.push_back(lcmod);
        }
      }
      
    }
  } 


}
Exemplo n.º 2
0
void
MultilinearFormulation::boundsOnProduct(ConstVariablePtr x1, ConstVariablePtr x2,
                                        double &lb, double &ub)
{
  double l1 = x1->getLb();
  double u1 = x1->getUb();
  double l2 = x2->getLb();
  double u2 = x2->getUb();

  lb = l1 * l2;
  ub = l1 * l2;

  lb = std::min(lb, u1*l2);
  ub = std::max(ub, u1*l2);

  lb = std::min(lb, u1*u2);
  ub = std::max(ub, u1*u2);

  lb = std::min(lb, l1*u2);
  ub = std::max(ub, l1*u2);

}
void
MultilinearTermsHandler::handleXDefConstraints_(RelaxationPtr relaxation, HandleCallingFunction wherefrom, ModVector &mods)
{
  for (UInt gix = 0; gix < groups_.size(); ++gix) {
    for(SetOfVars::const_iterator it = groups_[gix].begin(); it != groups_[gix].end(); ++it) {
      ConstVariablePtr xvar = *it;
      LinearFunctionPtr lf = (LinearFunctionPtr) new LinearFunction();
      lf->addTerm(xvar, -1.0);
      
      int pix = 0;
      for (std::set<SetOfVars>::iterator it2 = points_[gix].begin(); it2 != points_[gix].end(); ++it2) {
        VariablePtr lam = lambdavars_[gix][pix];
        double val = varIsAtLowerBoundAtPoint_(xvar, *it2) ? xvar->getLb() : xvar->getUb();
        lf->addTerm(lam, val);
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
        std::cout << xvar->getName() << ", lam: " << gix << "," << pix << " value is: " 
                  << val << std::endl;
#endif        
        ++pix;
      }      
      FunctionPtr f = (FunctionPtr) new Function(lf);

      if (wherefrom == relaxInit_Call) {
        ConstraintPtr c = relaxation->newConstraint(f, 0.0, 0.0);
        xConMap_.insert(std::make_pair(IntVarPtrPair(gix, xvar), c));
      }
      else { 
        IntVarPtrPairConstraintMap::iterator pos;
        pos = xConMap_.find(IntVarPtrPair(gix, xvar));
        if (pos == xConMap_.end()) {
          assert(0);
        }
        ConstraintPtr c = pos->second;
        //XXX Here you should just check if the constraint really was going to
        //change and do nothing if it doesn't...  (will be faster).
        if (wherefrom == relaxNodeInc_Call) {
          relaxation->changeConstraint(c, lf, 0.0, 0.0);
        }
        else {
          assert(0);
        }
        LinConModPtr lcmod = (LinConModPtr) new LinConMod(c, lf, 0.0, 0.0); 
        mods.push_back(lcmod);
      }      
    }
  }  
  
}
Exemplo n.º 4
0
BranchPtr CxUnivarHandler::doBranch_(BranchDirection UpOrDown,
                                     ConstVariablePtr v, double bvalue)
{
  BranchPtr branch;
  LinModsPtr linmods;

#if defined(DEBUG_CXUNIVARHANDLER)
  std::cout << "CxUnivarHandler, Branching: " << (UpOrDown == DownBranch ? "Down" : "Up")
            << " at value: " << bvalue << " on: " << std::endl;
  v->write(std::cout);
#endif

  // Zero out tmpX and grad each time, or else bad things happen
  for (UInt j = 0; j < tmpX_.size(); ++j) {
    tmpX_[j] = 0.0;
    grad_[j] = 0.0;
  }
    
  branch = (BranchPtr) new Branch();
  linmods = (LinModsPtr) new LinMods();

  // Change bounds on the x var (called v here)
  if (UpOrDown == DownBranch) {

    VarBoundModPtr mod = (VarBoundModPtr) new VarBoundMod(v, Upper, bvalue);
    linmods->insert(mod);

    // Find *all* cons_data that has v as an input variable.
    CxUnivarConstraintIterator dit; 
  
    for (dit = cons_data_.begin(); dit != cons_data_.end(); ++dit) {
      if ((*dit)->getRInputVar() == v) {

	ConstVariablePtr rov = (*dit)->getROutVar();
	FunctionPtr fn = (*dit)->getOriginalCon()->getFunction();
	int error;

	// Change the secant constraint
	ConstraintPtr secCon = (*dit)->getSecantCon();

	LinearFunctionPtr lf; 
	FunctionPtr f;

	double xlb = v->getLb();
	double xub = bvalue;

	// TODO: Check the error value!
	tmpX_[v->getIndex()] = xlb;
	double fxlb =  fn->eval(tmpX_, &error);
	tmpX_[v->getIndex()] = xub;
	double fxub =  fn->eval(tmpX_, &error);
	tmpX_[v->getIndex()] = 0.0;

	// TODO: check/remedy numerical issues in this division
	double m = 0.0;
	if (xub - xlb > 10e-7) {
	  m = (fxub - fxlb)/(xub - xlb);
	}
	double intercept = fxlb - m*xlb;
	lf = (LinearFunctionPtr) new LinearFunction();
	lf->addTerm(rov, 1.0);
	lf->addTerm(v, -m);

        LinConModPtr lcmod = (LinConModPtr) new LinConMod(secCon, lf,
                                                          -INFINITY,
                                                          intercept);
	linmods->insert(lcmod);

	// Change all linearization constraints
	ConstraintVector::iterator lin_it;
        for(lin_it = (*dit)->linConsBegin(); lin_it != (*dit)->linConsEnd();
            ++lin_it) {
	  ConstraintPtr c = *lin_it;
	}
      }
    }
  } else {
    VarBoundModPtr mod = (VarBoundModPtr) new VarBoundMod(v, Lower, bvalue);
    linmods->insert(mod);
  }

  assert(!"add Mod correctly here.");
  branch->addPMod(linmods);
  return branch;

}
Exemplo n.º 5
0
void CxUnivarConstraintData::addSecant(RelaxationPtr rel,
                                       ConstVariablePtr riv,
                                       ConstVariablePtr rov,
                                       FunctionPtr fn, DoubleVector& tmpX,
                                       bool init, ModVector &mods) 
{

  int error;
  double xlb, xub, fxlb, fxub, m, intercept;
  LinearFunctionPtr lf; 
  FunctionPtr f;

  // First add the secant inequalities based on variable bounds
  xlb = riv->getLb();
  xub = riv->getUb();
	
#if defined(DEBUG_CXUNIVARHANDLER)
  std::cout << "Adding secant on variable rix index: " << riv->getIndex() 
	    << " rov index: " << rov->getIndex()
	    << " xlb: " << xlb << " xub: " << xub << std::endl;
#endif 
  // no secant if unbounded either way
  if (xlb <= -0.9*INFINITY || xub >= 0.9*INFINITY) {
    std::cout << "Cannot add secant -- bound is infinite" << std::endl;
    return;
  }

  // TODO: Check the error value!
  tmpX[riv->getIndex()] = xlb;
  fxlb =  fn->eval(tmpX, &error);
  tmpX[riv->getIndex()] = xub;
  fxub =  fn->eval(tmpX, &error);
  tmpX[riv->getIndex()] = 0.0;

  // TODO: check/remedy numerical issues in this division
  if (xub - xlb > 10e-7) {
    m = (fxub - fxlb)/(xub - xlb);
  }
  else {
    m = 0.0;
  }

  intercept = fxlb - m*xlb;
  lf = (LinearFunctionPtr) new LinearFunction();
  lf->addTerm(rov, 1.0);
  lf->addTerm(riv, -m);

  // rovar <= m*rivar + intercept 
  if (init) {
     f = (FunctionPtr) new Function(lf);
     secCon_ = rel->newConstraint(f, -INFINITY, intercept);
  }
  else {
    rel->changeConstraint(secCon_, lf, -INFINITY, intercept);
    LinConModPtr lcmod = (LinConModPtr) new LinConMod(secCon_, lf, -INFINITY,
                                                      intercept);
    mods.push_back(lcmod);
  }

  
}
Exemplo n.º 6
0
void CxUnivarConstraintData::addLin(RelaxationPtr rel, ConstVariablePtr riv,
				    ConstVariablePtr rov, FunctionPtr fn,
                                    DoubleVector& tmpX, DoubleVector& grad,
                                    bool init, ModVector &mods)
{
 
  int error;
  ConstraintPtr cons; 
  double xlb = riv->getLb();
  double xub = riv->getUb();
  double fxlbval=0, fxubval=0, dfxlbval=0, dfxubval=0;
  double tmpxval, fxval, dfxval; 
  LinearFunctionPtr lf; 
  FunctionPtr f;

  // More sophisticated strategies hopefully could be obtained by simply
  // changing this array 
  int npts = 3;
  double xvals[] = {xlb, xub, (xub-xlb)/2.0};

#if defined(DEBUG_CXUNIVARHANDLER)
  std::cout << "Adding linearizations.  rix id: " << riv->getId() 
	    << " rix index: " << riv->getIndex() << " rov id: " << rov->getId() 
	    << " rov index: " << rov->getIndex()
	    << " xlb: " << xlb << " xub: " << xub << std::endl;
#endif
  
  for (int i = 0; i < npts; i++) {

    // Zero out tmpX and grad each time, or else bad things happen
    for (UInt j = 0; j < tmpX.size(); ++j) {
      tmpX[j] = 0.0;
      grad[j] = 0.0;
    }
    
    if (i == 2) {
      // Third linearization point taken to be where first two intersect:
      // x3 = (f'(xub)*xub - f'(xlb)*xlb + f(xlb) - f(xub))/(f'(xub) - f'(xlb))
      // Unless this would put it too close to one of the end points
      if (dfxubval - dfxlbval > 0.0001 || dfxubval - dfxlbval < -0.0001) {
        tmpxval = (dfxubval*xub - dfxlbval*xlb + fxlbval - fxubval)/
                  (dfxubval - dfxlbval);
        if (tmpxval < xlb + (xub-xlb)*0.05) {
          xvals[2] = xlb + (xub-xlb)*0.05;
        }
        else if (tmpxval > xub - (xub-xlb)*0.05) {
          xvals[2] = xub - (xub-xlb)*0.05;
        }
        else {
          xvals[2] = tmpxval;
        }
      }
    }
    tmpX[riv->getIndex()] = xvals[i];
    error = 0;
    fxval =  fn->eval(tmpX, &error);
    fn->evalGradient(&tmpX[0], &grad[0], &error);
#if defined(DEBUG_CXUNIVARHANDLER2)
    for (UInt j = 0; j < tmpX.size(); ++j) {
      std::cout << "x[" << j << "] = " << tmpX[j] << " dfdx[" << j << "] = "
                << grad[j] << std::endl;
    }
#endif
    dfxval = grad[riv->getIndex()];
    if (i == 0) {
       fxlbval = fxval;
       dfxlbval = dfxval; 
    }
    else if (i == 1) {
       fxubval = fxval;
       dfxubval = dfxval; 
    }
    // linearization:  rov >= f(xval) + f'(xval)(riv - xval) 
    //                 rov - f'(xval)*riv >= f(xval) - f'(xval)*xval
    lf = (LinearFunctionPtr) new LinearFunction();
    lf->addTerm(rov, 1.0);
    lf->addTerm(riv, -dfxval);
    if (init) {
        f = (FunctionPtr) new Function(lf);
    	cons = rel->newConstraint(f, fxval - dfxval*xvals[i], INFINITY);
	linCons_.push_back(cons);
    }
    else {
#if defined(DEBUG_CXUNIVARHANDLER)
       std::cout << "Will change 'linearization  ' constraint to have "
                 << "linear function: ";
       lf->write(std::cout);  
       std::cout << std::endl;
#endif

       rel->changeConstraint(linCons_[i], lf, fxval - dfxval*xvals[i], INFINITY); 
       LinConModPtr lcmod = (LinConModPtr) new LinConMod(linCons_[i], lf, 
                                                         fxval -
                                                         dfxval*xvals[i],
                                                         INFINITY); 
       mods.push_back(lcmod);
    }
  }
  tmpX[riv->getIndex()] = 0.0;
  grad[riv->getIndex()] = 0.0;

}
void MultilinearTermsHandler::getBranchingCandidates(RelaxationPtr, 
                                                const DoubleVector &x,
                                                ModVector &,
                                                BrVarCandSet &cands,
                                                BrCandVector &, bool &is_inf)
{
  // Implementation notes:
  //  (1) You must insert into the set cands
  //  (2) Super naive implmentation:  Just pick the variable from infeasible
  //      terms whose total 'bound product' is largest

  std::set<ConstVariablePtr> candidates;

  for (ConstTermIterator it = termsR_.begin(); it != termsR_.end(); ++it) {
    ConstVariablePtr zt = it->first;
    SetOfVars const &jt = it->second;

    if (allVarsBinary_(jt)) continue;

    double zval = x[zt->getIndex()];

#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      std::cout << "Relaxation term variable: ";
      zt->write(std::cout);
      std::cout << " Has LP value: " << zval << std::endl;
#endif

    double termval = 1.0;
    double largest_score = eTol_;
    ConstVariablePtr largest_score_var;
    for(SetOfVars::const_iterator jt_it = jt.begin(); jt_it != jt.end(); ++jt_it) {
      ConstVariablePtr termvar = *jt_it;
      termval *= x[termvar->getIndex()];
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      std::cout << "Term variable: ";
      termvar->write(std::cout);
      std::cout <<  "  has value: " << x[termvar->getIndex()] << std::endl;
#endif

      double score = (termvar->getUb() - x[termvar->getIndex()])*
        (x[termvar->getIndex()] - termvar->getLb());

      if (score > largest_score) {
        largest_score = score;
        largest_score_var = termvar;
      }
    }
    if (fabs(zval - termval) > eTol_) {
      candidates.insert(largest_score_var);
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      largest_score_var->write(std::cout);
      std::cout << " will be a candidate" << std::endl;      
#endif
    }
    
  }

#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
  std::cout << "Branching candidates are: " << std::endl;
  for(SetOfVars::const_iterator it = candidates.begin(); it != candidates.end(); ++it) {
    (*it)->write(std::cout);
  }
#endif  

  for(SetOfVars::const_iterator it = candidates.begin(); it != candidates.end(); ++it) {
    ConstVariablePtr v = *it;
    BrVarCandPtr br_can = (BrVarCandPtr) new BrVarCand(v, v->getIndex(), 0.5, 0.5);
    cands.insert(br_can);
  }
  is_inf = false;
}
ModificationPtr MultilinearTermsHandler::getBrMod(BrCandPtr cand, DoubleVector &xval, 
                                                  RelaxationPtr , BranchDirection dir)
{
  LinModsPtr linmods;

  //XXX Put (bool init) back in handle{x,z}def...

  BrVarCandPtr  vcand = boost::dynamic_pointer_cast <BrVarCand> (cand);
  VariablePtr v = vcand->getVar();
  
  double branching_value = xval[v->getIndex()];
  BoundType lu;
  VariableType vtype = v->getType();

  // Change bounds on the x var (called v here)
  if (dir == DownBranch) { 
    lu = Upper;    
    if (vtype != Continuous)  branching_value = floor(branching_value);
  }
  else {
    lu = Lower;
    if (vtype != Continuous)  branching_value = ceil(branching_value);
  }

  linmods = (LinModsPtr) new LinMods();

  VarBoundModPtr vmod = (VarBoundModPtr) new VarBoundMod(v, lu, branching_value);
  linmods->insert(vmod);
  
  
  // This chunk of code changes the
  // x_{V_g} = \sum_{k=1}^{2 |V_g|} \lambda_k^g \chi^{k,g} \forall g \in G


  for (UInt gix = 0; gix < groups_.size(); ++gix) {
    for(SetOfVars::const_iterator it = groups_[gix].begin(); it != groups_[gix].end(); ++it) {
      ConstVariablePtr xvar = *it;
      if (v != xvar) continue;

      LinearFunctionPtr lf = (LinearFunctionPtr) new LinearFunction();
      lf->addTerm(xvar, -1.0);

      UInt pix = 0;
      for (std::set<SetOfVars>::iterator it2 = points_[gix].begin(); it2 != points_[gix].end(); ++it2) {
        VariablePtr lam = lambdavars_[gix][pix];
        double val = -INFINITY;

        bool atLower = varIsAtLowerBoundAtPoint_(v, *it2);
        bool atUpper = !atLower;
        
        if (lu == Upper && atUpper) val = branching_value;
        else if (lu == Lower && atLower) val = branching_value;
        else val = (atLower ? v->getLb() : v->getUb());

        lf->addTerm(lam, val);
        ++pix;
      }       
      FunctionPtr f = (FunctionPtr) new Function(lf);

      IntVarPtrPairConstraintMap::iterator pos;
      pos = xConMap_.find(IntVarPtrPair(gix, xvar));
      if (pos == xConMap_.end()) {
        assert(0);
      }
      ConstraintPtr c = pos->second;

      LinConModPtr lcmod = (LinConModPtr) new LinConMod(c, lf, 0.0, 0.0);
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      std::cout << "getBrMod().  Will change 'x =' constraint to have linear function ";
      lf->write(std::cout);        
      std::cout << std::endl;
#endif
      linmods->insert(lcmod);
    
    }
  }

  // This will change the z_t = sum \sum_{k=1}^{2|V_g} \lambda_k^g \chi^{k,g}.
  //  Probably not very efficient way to do this...
  for(ConstTermIterator it = termsR_.begin(); it != termsR_.end(); ++it) {
    SetOfVars const &jt = it->second;

    for (UInt gix = 0; gix < groups_.size(); ++gix) {
      SetOfVars &vg = groups_[gix];

      std::set<ConstVariablePtr>::iterator pos1;
      pos1 = jt.find(v);
      if (pos1 == jt.end()) continue; // J_t does not contain v, go to next group
      // J_t is not in V_g, go to next group
      if (! std::includes(vg.begin(), vg.end(), jt.begin(), jt.end())) continue;

      ConstVariablePtr zvar = it->first;
      LinearFunctionPtr lf = (LinearFunctionPtr) new LinearFunction();
      lf->addTerm(zvar, -1.0);

      // Get ConstraintToChange
      IntVarPtrPairConstraintMap::iterator pos2;
      pos2 = zConMap_.find(IntVarPtrPair(gix, zvar));
      if (pos2 == zConMap_.end()) {
        assert(0);
      }
      ConstraintPtr c = pos2->second;

      UInt pix = 0;
      for (std::set<SetOfVars>::iterator it2 = points_[gix].begin(); 
           it2 != points_[gix].end(); ++it2) {

        double prodval = 1.0;
        VariablePtr lam = lambdavars_[gix][pix];

        // Compute new extreme point value for this lambda
        for(SetOfVars::const_iterator jt_it = jt.begin(); jt_it != jt.end(); ++jt_it) {
          ConstVariablePtr xvar = *jt_it;
          double val = 0.0;
          bool atLower = varIsAtLowerBoundAtPoint_(xvar, *it2);
          bool atUpper = !atLower;
            
          if (xvar == v) {
            if (lu == Upper && atUpper) val = branching_value;
            else if (lu == Lower && atLower) val = branching_value;
            else val = (atLower ? xvar->getLb() : xvar->getUb());
          }
          else {
            val = atLower ? xvar->getLb() : xvar->getUb();
          }            
          prodval *= val;
        }
        lf->addTerm(lam, prodval);
        ++pix;
      }

      // Add new mod
      LinConModPtr lcmod = (LinConModPtr) new LinConMod(c, lf, 0.0, 0.0);

#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      std::cout << "getBrMod(): Will change 'zt = ' constraint to have linear function: ";
      lf->write(std::cout);  
      std::cout << std::endl;
#endif
      linmods->insert(lcmod);
    }
          
  }

  return linmods;

  return ModificationPtr();
}