// 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); } } } } }
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); } } } }
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; }
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); } }
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(); }