From 59bb4f2dcc2c0b9bffea23dca3867f2e6cb27bf6 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 16:09:44 +0200 Subject: [PATCH 01/11] Add support for indicator constraints in MPSolver Signed-off-by: Peter Mitri --- ortools/linear_solver/CMakeLists.txt | 8 ++- ortools/linear_solver/java/linear_solver.i | 1 + ortools/linear_solver/linear_solver.cc | 21 +++++- ortools/linear_solver/linear_solver.h | 9 +++ ortools/linear_solver/python/linear_solver.i | 1 + ortools/linear_solver/scip_interface_test.cc | 69 ++++++++++++++++++++ 6 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 ortools/linear_solver/scip_interface_test.cc diff --git a/ortools/linear_solver/CMakeLists.txt b/ortools/linear_solver/CMakeLists.txt index 74d20df48bc..b4272d6c32b 100644 --- a/ortools/linear_solver/CMakeLists.txt +++ b/ortools/linear_solver/CMakeLists.txt @@ -82,11 +82,17 @@ if(BUILD_TESTING) set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:$ORIGIN:$ORIGIN/../lib:$ORIGIN") endif () + if(USE_SCIP) + add_executable(test_scip_interface scip_interface_test.cc) + target_compile_features(test_scip_interface PRIVATE cxx_std_17) + target_link_libraries(test_scip_interface PRIVATE ortools::ortools GTest::gtest_main) + add_test(NAME cxx_unittests_scip_interface COMMAND test_scip_interface) + endif() + if(USE_XPRESS) add_executable(test_xprs_interface xpress_interface_test.cc) target_compile_features(test_xprs_interface PRIVATE cxx_std_17) target_link_libraries(test_xprs_interface PRIVATE ortools::ortools GTest::gtest_main) - add_test(NAME cxx_unittests_xpress_interface COMMAND test_xprs_interface) endif() endif () diff --git a/ortools/linear_solver/java/linear_solver.i b/ortools/linear_solver/java/linear_solver.i index 855fa43291d..882364c9114 100644 --- a/ortools/linear_solver/java/linear_solver.i +++ b/ortools/linear_solver/java/linear_solver.i @@ -347,6 +347,7 @@ PROTO2_RETURN( %rename (makeConstraint) operations_research::MPSolver::MakeRowConstraint(); %rename (makeConstraint) operations_research::MPSolver::MakeRowConstraint(double, double, const std::string&); %rename (makeConstraint) operations_research::MPSolver::MakeRowConstraint(const std::string&); +%rename (makeIndicatorConstraint) operations_research::MPSolver::MakeIndicatorConstraint; // Expose the MPSolver's basic API, with trivial renames. %rename (makeBoolVar) operations_research::MPSolver::MakeBoolVar; // no test diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index b8dd07a5703..9d991ecff66 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1511,6 +1511,23 @@ MPConstraint* MPSolver::MakeRowConstraint(const LinearRange& range, return constraint; } +MPConstraint* MPSolver::MakeIndicatorConstraint( + double lb, double ub, const std::string& name, + const MPVariable* indicator_variable) { + const int constraint_index = NumConstraints(); + MPConstraint* const constraint = + new MPConstraint(constraint_index, lb, ub, name, interface_.get()); + constraint->indicator_variable_ = indicator_variable; + 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; +} + int MPSolver::ComputeMaxConstraintSize(int min_constraint_index, int max_constraint_index) const { int max_constraint_size = 0; @@ -1530,8 +1547,8 @@ bool MPSolver::HasInfeasibleConstraints() const { for (int i = 0; i < static_cast(constraints_.size()); ++i) { if (constraints_[i]->lb() > constraints_[i]->ub()) { LOG(WARNING) << "Constraint " << constraints_[i]->name() << " (" << i - << ") has contradictory bounds:" << " lower bound = " - << constraints_[i]->lb() + << ") has contradictory bounds:" + << " lower bound = " << constraints_[i]->lb() << " upper bound = " << constraints_[i]->ub(); hasInfeasibleConstraints = true; } diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 0b363d5d307..a07a18ee809 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -443,6 +443,12 @@ class MPSolver { MPConstraint* MakeRowConstraint(const LinearRange& range, const std::string& name); + /// Creates a named indicator constraint with given bounds and given + /// indicator variable. + MPConstraint* MakeIndicatorConstraint(double lb, double ub, + const std::string& name, + const MPVariable* indicator_variable); + /** * Returns the objective object. * @@ -1349,6 +1355,9 @@ class MPConstraint { */ void set_is_lazy(bool laziness) { is_lazy_ = laziness; } + void set_indicator_variable(const MPVariable* variable) { + indicator_variable_ = variable; + } const MPVariable* indicator_variable() const { return indicator_variable_; } bool indicator_value() const { return indicator_value_; } diff --git a/ortools/linear_solver/python/linear_solver.i b/ortools/linear_solver/python/linear_solver.i index c73d11807c2..970274a8cdd 100644 --- a/ortools/linear_solver/python/linear_solver.i +++ b/ortools/linear_solver/python/linear_solver.i @@ -329,6 +329,7 @@ PY_CONVERT(MPVariable); %rename (Constraint) operations_research::MPSolver::MakeRowConstraint(); %rename (Constraint) operations_research::MPSolver::MakeRowConstraint(double, double, const std::string&); %rename (Constraint) operations_research::MPSolver::MakeRowConstraint(const std::string&); +%rename (IndicatorConstraint) operations_research::MPSolver::MakeIndicatorConstraint; %unignore operations_research::MPSolver::~MPSolver; %newobject operations_research::MPSolver::CreateSolver; %unignore operations_research::MPSolver::CreateSolver; diff --git a/ortools/linear_solver/scip_interface_test.cc b/ortools/linear_solver/scip_interface_test.cc new file mode 100644 index 00000000000..d48350ec565 --- /dev/null +++ b/ortools/linear_solver/scip_interface_test.cc @@ -0,0 +1,69 @@ +// Copyright 2010-2024 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gtest/gtest.h" +#include "ortools/base/init_google.h" +#include "ortools/linear_solver/linear_solver.h" + +namespace operations_research { + +TEST(ScipInterface, IndicatorConstraint0) { + MPSolver solver("SCIP", MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING); + // Maximize x <= 100 + auto x = solver.MakeNumVar(0, 100, "x"); + solver.MutableObjective()->SetMaximization(); + solver.MutableObjective()->SetCoefficient(x, 1); + // With indicator constraint + // if var = 0, then x <= 10 + auto var = solver.MakeBoolVar("indicator_var"); + auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var); + ct->SetCoefficient(x, 1); + + // Force var to 0 ==> x = 10 + var->SetUB(0); + solver.Solve(); + EXPECT_EQ(x->solution_value(), 10); +} + +TEST(ScipInterface, IndicatorConstraint1) { + MPSolver solver("SCIP", MPSolver::SCIP_MIXED_INTEGER_PROGRAMMING); + // Maximize x <= 100 + auto x = solver.MakeNumVar(0, 100, "x"); + solver.MutableObjective()->SetMaximization(); + solver.MutableObjective()->SetCoefficient(x, 1); + // With indicator constraint + // if var = 0, then x <= 10 + auto var = solver.MakeBoolVar("indicator_var"); + auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var); + ct->SetCoefficient(x, 1); + + // Leave var free ==> x = 100 + solver.Solve(); + EXPECT_EQ(var->solution_value(), 1); + EXPECT_EQ(x->solution_value(), 100); +} +} + +int main(int argc, char** argv) { + absl::SetFlag(&FLAGS_stderrthreshold, 0); + testing::InitGoogleTest(&argc, argv); + auto solver = operations_research::MPSolver::CreateSolver("scip"); + if (solver == nullptr) { + LOG(ERROR) << "SCIP solver is not available"; + return EXIT_SUCCESS; + } else { + return RUN_ALL_TESTS(); + } +} \ No newline at end of file From f243c06924b0f13c3a152194b5bbdded49d15451 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 16:13:11 +0200 Subject: [PATCH 02/11] revert setter Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index a07a18ee809..dab25e1214e 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -1354,10 +1354,7 @@ class MPConstraint { * For more info see: http://tinyurl.com/lazy-constraints. */ void set_is_lazy(bool laziness) { is_lazy_ = laziness; } - - void set_indicator_variable(const MPVariable* variable) { - indicator_variable_ = variable; - } + const MPVariable* indicator_variable() const { return indicator_variable_; } bool indicator_value() const { return indicator_value_; } From 73b8e15cd2c3e15576e31f83d974484e4a94111e Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 16:14:27 +0200 Subject: [PATCH 03/11] clang-format Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.h | 2 +- ortools/linear_solver/scip_interface_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index dab25e1214e..17269c98a02 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -1354,7 +1354,7 @@ class MPConstraint { * For more info see: http://tinyurl.com/lazy-constraints. */ void set_is_lazy(bool laziness) { is_lazy_ = laziness; } - + const MPVariable* indicator_variable() const { return indicator_variable_; } bool indicator_value() const { return indicator_value_; } diff --git a/ortools/linear_solver/scip_interface_test.cc b/ortools/linear_solver/scip_interface_test.cc index d48350ec565..678cc4aefe6 100644 --- a/ortools/linear_solver/scip_interface_test.cc +++ b/ortools/linear_solver/scip_interface_test.cc @@ -54,7 +54,7 @@ TEST(ScipInterface, IndicatorConstraint1) { EXPECT_EQ(var->solution_value(), 1); EXPECT_EQ(x->solution_value(), 100); } -} +} // namespace operations_research int main(int argc, char** argv) { absl::SetFlag(&FLAGS_stderrthreshold, 0); From 4de1bfcf36af090e53f7bee19747b590530e497a Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 16:27:41 +0200 Subject: [PATCH 04/11] todo + cleanup Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 9d991ecff66..ebf56323086 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1517,6 +1517,7 @@ MPConstraint* MPSolver::MakeIndicatorConstraint( 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; if (constraint_name_to_index_) { gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(), @@ -1547,8 +1548,8 @@ bool MPSolver::HasInfeasibleConstraints() const { for (int i = 0; i < static_cast(constraints_.size()); ++i) { if (constraints_[i]->lb() > constraints_[i]->ub()) { LOG(WARNING) << "Constraint " << constraints_[i]->name() << " (" << i - << ") has contradictory bounds:" - << " lower bound = " << constraints_[i]->lb() + << ") has contradictory bounds:"<< " lower bound = " + << constraints_[i]->lb() << " upper bound = " << constraints_[i]->ub(); hasInfeasibleConstraints = true; } From 534c91c5fa65636f1b8fbf9beb60e19a4b3a096a Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 16:54:51 +0200 Subject: [PATCH 05/11] revert bad change Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index ebf56323086..904d6b7e588 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1548,7 +1548,7 @@ bool MPSolver::HasInfeasibleConstraints() const { for (int i = 0; i < static_cast(constraints_.size()); ++i) { if (constraints_[i]->lb() > constraints_[i]->ub()) { LOG(WARNING) << "Constraint " << constraints_[i]->name() << " (" << i - << ") has contradictory bounds:"<< " lower bound = " + << ") has contradictory bounds:" << " lower bound = " << constraints_[i]->lb() << " upper bound = " << constraints_[i]->ub(); hasInfeasibleConstraints = true; From a0e5dfd87e983301d43e72c4659afa9539d85ada Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Fri, 12 Jul 2024 17:12:16 +0200 Subject: [PATCH 06/11] use indicator_value Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 3 ++- ortools/linear_solver/linear_solver.h | 3 ++- ortools/linear_solver/scip_interface_test.cc | 18 ++++++++++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 904d6b7e588..8da314a10b5 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1513,12 +1513,13 @@ MPConstraint* MPSolver::MakeRowConstraint(const LinearRange& range, MPConstraint* MPSolver::MakeIndicatorConstraint( double lb, double ub, const std::string& name, - const MPVariable* indicator_variable) { + const MPVariable* indicator_variable, bool indicator_value) { 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 (constraint_name_to_index_) { gtl::InsertOrDie(&*constraint_name_to_index_, constraint->name(), constraint_index); diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 17269c98a02..62514326fc0 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -447,7 +447,8 @@ class MPSolver { /// indicator variable. MPConstraint* MakeIndicatorConstraint(double lb, double ub, const std::string& name, - const MPVariable* indicator_variable); + const MPVariable* indicator_variable, + bool indicator_value); /** * Returns the objective object. diff --git a/ortools/linear_solver/scip_interface_test.cc b/ortools/linear_solver/scip_interface_test.cc index 678cc4aefe6..c0e573598c0 100644 --- a/ortools/linear_solver/scip_interface_test.cc +++ b/ortools/linear_solver/scip_interface_test.cc @@ -28,9 +28,14 @@ TEST(ScipInterface, IndicatorConstraint0) { // With indicator constraint // if var = 0, then x <= 10 auto var = solver.MakeBoolVar("indicator_var"); - auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var); + auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var, false); ct->SetCoefficient(x, 1); + // Leave var free ==> x = 100 + solver.Solve(); + EXPECT_EQ(var->solution_value(), 1); + EXPECT_EQ(x->solution_value(), 100); + // Force var to 0 ==> x = 10 var->SetUB(0); solver.Solve(); @@ -44,15 +49,20 @@ TEST(ScipInterface, IndicatorConstraint1) { solver.MutableObjective()->SetMaximization(); solver.MutableObjective()->SetCoefficient(x, 1); // With indicator constraint - // if var = 0, then x <= 10 + // if var = 1, then x <= 10 auto var = solver.MakeBoolVar("indicator_var"); - auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var); + auto ct = solver.MakeIndicatorConstraint(0, 10, "test", var, true); ct->SetCoefficient(x, 1); // Leave var free ==> x = 100 solver.Solve(); - EXPECT_EQ(var->solution_value(), 1); + EXPECT_EQ(var->solution_value(), 0); EXPECT_EQ(x->solution_value(), 100); + + // Force var to 0 ==> x = 10 + var->SetLB(1); + solver.Solve(); + EXPECT_EQ(x->solution_value(), 10); } } // namespace operations_research From 52547b151016375221ddc3abe1b442f21bf17f3c Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 17 Jul 2024 14:07:54 +0200 Subject: [PATCH 07/11] review Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 12 ++++++++++-- ortools/linear_solver/linear_solver.h | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 8da314a10b5..377a366d239 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -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 || + indicator_variable->ub() != 1) { + LOG(ERROR) << "Variable " << indicator_variable->name() + << " is not boolean"; + 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"; + 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; } diff --git a/ortools/linear_solver/linear_solver.h b/ortools/linear_solver/linear_solver.h index 62514326fc0..59d9c536848 100644 --- a/ortools/linear_solver/linear_solver.h +++ b/ortools/linear_solver/linear_solver.h @@ -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, From 888963d5f2c4edbad373f8c3d984c7ae2c0db553 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 17 Jul 2024 14:57:24 +0200 Subject: [PATCH 08/11] Update ortools/linear_solver/linear_solver.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Florian Omnès --- ortools/linear_solver/linear_solver.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 377a366d239..142ac7ce7c3 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1516,8 +1516,8 @@ MPConstraint* MPSolver::MakeIndicatorConstraint( const MPVariable* indicator_variable, bool indicator_value) { if (!indicator_variable->integer() || indicator_variable->lb() != 0 || indicator_variable->ub() != 1) { - LOG(ERROR) << "Variable " << indicator_variable->name() - << " is not boolean"; + LOG(ERROR) << "Error adding indicator constraint " << name << ". Variable " << indicator_variable->name() + << " is not Boolean"; return nullptr; } const int constraint_index = NumConstraints(); From 71aeeb83f4031f091c5a7970b1b09f38fccabcef Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 17 Jul 2024 14:58:12 +0200 Subject: [PATCH 09/11] review Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 142ac7ce7c3..3c63f2c6ade 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1516,8 +1516,8 @@ MPConstraint* MPSolver::MakeIndicatorConstraint( const MPVariable* indicator_variable, bool indicator_value) { if (!indicator_variable->integer() || indicator_variable->lb() != 0 || indicator_variable->ub() != 1) { - LOG(ERROR) << "Error adding indicator constraint " << name << ". Variable " << indicator_variable->name() - << " is not Boolean"; + LOG(ERROR) << "Error adding indicator constraint " << name << ". Variable " + << indicator_variable->name() << " is not Boolean"; return nullptr; } const int constraint_index = NumConstraints(); @@ -1526,7 +1526,6 @@ MPConstraint* MPSolver::MakeIndicatorConstraint( constraint->indicator_variable_ = indicator_variable; constraint->indicator_value_ = indicator_value; if (!interface_->AddIndicatorConstraint(constraint)) { - LOG(ERROR) << "Solver doesn't support indicator constraints"; return nullptr; } if (constraint_name_to_index_) { From b4f91fb2b6451a768711fb9aceb30aa3df6cc3cc Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 17 Jul 2024 17:33:36 +0200 Subject: [PATCH 10/11] review Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 3c63f2c6ade..022e72fbc49 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1514,6 +1514,9 @@ MPConstraint* MPSolver::MakeRowConstraint(const LinearRange& range, MPConstraint* MPSolver::MakeIndicatorConstraint( double lb, double ub, const std::string& name, const MPVariable* indicator_variable, bool indicator_value) { + DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(indicator_variable)) + << indicator_variable; + if (indicator_variable == nullptr) return nullptr; if (!indicator_variable->integer() || indicator_variable->lb() != 0 || indicator_variable->ub() != 1) { LOG(ERROR) << "Error adding indicator constraint " << name << ". Variable " From d68a748ee3a102f34cfdddfc6221cc7585bff6b2 Mon Sep 17 00:00:00 2001 From: Peter Mitri Date: Wed, 17 Jul 2024 17:34:00 +0200 Subject: [PATCH 11/11] review Signed-off-by: Peter Mitri --- ortools/linear_solver/linear_solver.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ortools/linear_solver/linear_solver.cc b/ortools/linear_solver/linear_solver.cc index 022e72fbc49..1b2f75238b7 100644 --- a/ortools/linear_solver/linear_solver.cc +++ b/ortools/linear_solver/linear_solver.cc @@ -1514,7 +1514,7 @@ MPConstraint* MPSolver::MakeRowConstraint(const LinearRange& range, MPConstraint* MPSolver::MakeIndicatorConstraint( double lb, double ub, const std::string& name, const MPVariable* indicator_variable, bool indicator_value) { - DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(indicator_variable)) + DLOG_IF(DFATAL, !interface_->solver_->OwnsVariable(indicator_variable)) << indicator_variable; if (indicator_variable == nullptr) return nullptr; if (!indicator_variable->integer() || indicator_variable->lb() != 0 ||