Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for indicator constraints in MPSolver #132

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
12 changes: 10 additions & 2 deletions ortools/linear_solver/linear_solver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1514,19 +1514,27 @@ MPConstraint* MPSolver::MakeRowConstraint(const LinearRange& range,
MPConstraint* MPSolver::MakeIndicatorConstraint(
double lb, double ub, const std::string& name,
const MPVariable* indicator_variable, bool indicator_value) {
if (!indicator_variable->integer() || indicator_variable->lb() != 0 ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be consistent with e.g MPObjective::SetCoefficient and MPConstraint::SetCoefficient, you'd need the following lines

Although the 2nd line is currently included in the 1st.

DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(indicator_variable)) << indicator_variable;
if (indicator_variable == nullptr) return nullptr;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

indicator_variable->ub() != 1) {
LOG(ERROR) << "Variable " << indicator_variable->name()
<< " is not boolean";
pet-mit marked this conversation as resolved.
Show resolved Hide resolved
return nullptr;
}
const int constraint_index = NumConstraints();
MPConstraint* const constraint =
new MPConstraint(constraint_index, lb, ub, name, interface_.get());
// TODO: check that variable is boolean?
constraint->indicator_variable_ = indicator_variable;
constraint->indicator_value_ = indicator_value;
if (!interface_->AddIndicatorConstraint(constraint)) {
LOG(ERROR) << "Solver doesn't support indicator constraints";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's necessary to display a log message here, it's already done in the base version of AddIndicatorConstraint (linear_solver.cc)

virtual bool AddIndicatorConstraint(MPConstraint* const /*ct*/) {
  LOG(ERROR) << "Solver doesn't support indicator constraints.";
  return false;
}

It would be displayed twice. Not terrible, but not great either.

Copy link
Collaborator Author

@pet-mit pet-mit Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, but then for interfaces that can sometimes handle indicator constraints, sometimes not (for example an interface that can handle MIP or LP problems), we'll have to log the issue before returning "false"

return nullptr;
}
if (constraint_name_to_index_) {
gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(),
constraint_index);
}
constraints_.push_back(constraint);
constraint_is_extracted_.push_back(false);
interface_->AddIndicatorConstraint(constraint);
return constraint;
}

Expand Down
3 changes: 3 additions & 0 deletions ortools/linear_solver/linear_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,9 @@ class MPSolver {

/// Creates a named indicator constraint with given bounds and given
/// indicator variable.
/// The constraint is active if and only if *indicator_variable has value
/// indicator_value
/// (Only available for MILP problems)
MPConstraint* MakeIndicatorConstraint(double lb, double ub,
const std::string& name,
const MPVariable* indicator_variable,
Expand Down