bool
MultilinearTermsHandler::isFeasible(ConstSolutionPtr sol, RelaxationPtr ,
                                    bool &, double &)
{
  const double *x = sol->getPrimal();
  bool is_feas = true;

#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
  std::cout << "Checking feasibility: " << std::endl;
#endif

  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()];
    double xval = 1.0;
    for(SetOfVars::const_iterator jt_it = jt.begin(); jt_it != jt.end(); ++jt_it) {
      xval *= x[(*jt_it)->getIndex()];
    }
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
    std::cout << "Term for variable: " << std::endl;
    zt->write(std::cout);
    std::cout << " has error: " << fabs(zval - xval) << std::endl;
#endif
    if (fabs(zval - xval) > eTol_) {
      is_feas = false;
      break;
    }
  }
  
  return(is_feas);
}
void 
Hypergraph::create(std::map<ConstVariablePtr, SetOfVars > const &terms)
{

  // Add the vertices
  std::map<ConstVariablePtr, SetOfVars >::const_iterator terms_it;
  for(terms_it = terms.begin(); terms_it != terms.end(); ++terms_it) {
    SetOfVars const &jt = terms_it->second;
    for(SetOfVars::iterator it = jt.begin(); it != jt.end(); ++it) {
      V_.insert(*it);
    }
  }

  // Add empty lists for the hyperedges
  for(SetOfVars::iterator v_it = V_.begin(); v_it != V_.end(); ++v_it) {
    std::list<SetOfVars> e_list;
    adjList_.insert(make_pair(*v_it, e_list));
  }

  // Now add the edges
  for(terms_it = terms.begin(); terms_it != terms.end(); ++terms_it) {
    SetOfVars const &jt = terms_it->second;
    E_.insert(jt);
    // Put it in the adjacency lists
    for (SetOfVars::const_iterator it = jt.begin(); it != jt.end(); ++it) {
      AdjListType::iterator pos = adjList_.find(*it);
      assert(pos != adjList_.end());
      std::list<SetOfVars> &e_list = pos->second;
      e_list.push_back(jt);
    }
    
    // Determine weight
    ConstVariablePtr zvar = terms_it->first;
    double zweight = 0.0;
    for (ConstrSet::iterator it2 = zvar->consBegin(); it2 != zvar->consEnd(); ++it2) {
      const LinearFunctionPtr lf = (*it2)->getLinearFunction();
      double w = lf->getWeight(zvar);
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      zvar->write(std::cout);
      std::cout << "  has weight: " << w << " in constraint: ";
      (*it2)->write(std::cout);
#endif
      zweight += fabs(w);
    }

    // Add objective weight
    const LinearFunctionPtr obj = problem_->getObjective()->getLinearFunction();
    if (obj != 0) {
      double w = obj->getWeight(zvar);
      zweight += fabs(w);
    }

    weights_.insert(make_pair(jt, zweight));
    originalWeights_.insert(make_pair(jt, zweight));
  }
}
void
Hypergraph::write(std::ostream &out) const
{
  for(AdjListType::const_iterator it = adjList_.begin(); it != adjList_.end(); ++it) {
    ConstVariablePtr v = it->first;
    std::cout << "Vertex: ";
    v->write(out);
    std::list<SetOfVars> e_list = it->second;    
    for(std::list<SetOfVars>::const_iterator e_it = e_list.begin(); e_it != e_list.end(); ++e_it) {
      std::cout << " has edge: " << std::endl;    
      for(SetOfVars::const_iterator v_it = e_it->begin(); v_it != e_it->end(); ++v_it) {
        (*v_it)->write(out);
      }
    }
  }    
}
void
MultilinearTermsHandler::setupWeights_()
{
  for(ConstTermIterator it = termsR_.begin(); it != termsR_.end(); ++it) {
    ConstVariablePtr zvar = it->first;
    double zweight = 0.0;
    for (ConstrSet::iterator it2 = zvar->consBegin(); it2 != zvar->consEnd(); ++it2) {
      const LinearFunctionPtr lf = (*it2)->getLinearFunction();
      double w = lf->getWeight(zvar);
#if defined(DEBUG_MULTILINEARTERMS_HANDLER)
      zvar->write(std::cout);
      std::cout << "  has weight: " << w << " in constraint: ";
      (*it2)->write(std::cout);
#endif
      zweight += fabs(w);
    }
    weights_.insert(std::make_pair(zvar, zweight));
  }
  
}
BranchPtr
MultilinearTermsHandler::doBranch_(BranchDirection UpOrDown, ConstVariablePtr v, 
                                   double bvalue)
{
  BranchPtr branch;
  BoundType lu;
  VariableType vtype = v->getType();

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

  branch = (BranchPtr) new Branch();

  double branching_value = bvalue;

  // Change bounds on the x var (called v here)
  if (UpOrDown == DownBranch) { 
    lu = Upper;    
    if (vtype != Continuous)  branching_value = floor(bvalue);
  }
  else {
    lu = Lower;
    if (vtype != Continuous)  branching_value = ceil(bvalue);
  }
 
  VarBoundModPtr vmod = (VarBoundModPtr) new VarBoundMod(v, lu, branching_value);
  assert(!"check whether this needs to be addRMod instead");
  branch->addPMod(vmod);

  branch->setActivity(0.5);// TODO: set this correctly
  return branch;

}
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 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;
}