From 9cf6faac82aabc6487528e088ba7c95dee075b30 Mon Sep 17 00:00:00 2001 From: Gleb Belov Date: Wed, 22 May 2024 14:34:50 +1000 Subject: [PATCH] Multi-obj: HiGHS model update #239 --- include/mp/backend-std.h | 2 +- include/mp/flat/converter_multiobj.h | 23 ++++++++++++++---- solvers/highsmp/highsmpmodelapi.cc | 36 +++++++++++++++------------- solvers/highsmp/highsmpmodelapi.h | 4 ++-- solvers/visitor/visitormodelapi.h | 2 ++ 5 files changed, 44 insertions(+), 23 deletions(-) diff --git a/include/mp/backend-std.h b/include/mp/backend-std.h index 2ef814c91..52ec088cf 100644 --- a/include/mp/backend-std.h +++ b/include/mp/backend-std.h @@ -269,7 +269,7 @@ class StdBackend : while (GetMM().PrepareSolveIteration()) { Solve(); SetStatus( GetSolveResult() ); // before GetSolution() - sol_last_ = GetSolution(); + sol_last_ = GetSolution(); // @todo don't need it in the last iteration GetMM().ProcessIterationSolution(sol_last_, status_.first); } } diff --git a/include/mp/flat/converter_multiobj.h b/include/mp/flat/converter_multiobj.h index 1d1bf9081..3dbec2ec2 100644 --- a/include/mp/flat/converter_multiobj.h +++ b/include/mp/flat/converter_multiobj.h @@ -107,21 +107,36 @@ class MOManager { obj_new_ = MPD( get_objectives() ); // no linking if (MPD( GetEnv() ).verbose_mode()) MPD( GetEnv() ).Print( - "\n\nMULTIOBJECTIVE MODE WITH {} OBJECTIVES.\n", obj_new_.size()); + "\n\n" + "==============================================================================\n" + "MULTI-OBJECTIVE MODE: starting with {} objectives ...\n" + "==============================================================================\n" + "==============================================================================\n\n" + , obj_new_.size()); } /// Do prepare next solve bool DoPrepareNextMultiobjSolve() { if (++i_current_obj_ >= obj_new_.size()) { status_ = MOManagerStatus::FINISHED; + MPD( GetEnv() ).Print( + "\n\n" + "==============================================================================\n" + "MULTI-OBJECTIVE MODE: done.\n\n"); return false; // all done } + if (MPD( GetEnv() ).verbose_mode()) + MPD( GetEnv() ).Print( + "\n\n" + "MULTI-OBJECTIVE MODE: objective {} (out of {}) ...\n" + "==============================================================================\n\n" + , i_current_obj_+1, obj_new_.size()); + MPD( GetModelAPI() ).InitProblemModificationPhase( + MPD( GetModelInfo() )); ReplaceCurrentObj(); if (i_current_obj_) RestrictLastObjVal(); - if (MPD( GetEnv() ).verbose_mode()) - MPD( GetEnv() ).Print( - "\n\nMULTIOBJECTIVE MODE: OBJECTIVE {} OUT OF {}.\n", i_current_obj_+1, obj_new_.size()); + MPD( GetModelAPI() ).FinishProblemModificationPhase(); return true; } diff --git a/solvers/highsmp/highsmpmodelapi.cc b/solvers/highsmp/highsmpmodelapi.cc index 7cd67fd29..d03b7af83 100644 --- a/solvers/highsmp/highsmpmodelapi.cc +++ b/solvers/highsmp/highsmpmodelapi.cc @@ -31,12 +31,14 @@ void HighsModelAPI::AddVariables(const VarArrayDef& v) { void HighsModelAPI::SetLinearObjective( int iobj, const LinearObjective& lo ) { if (iobj < 1) { - // Highs_changeObjectiveOffset(highs, offset); TODO offset? - HIGHS_CCALL(Highs_changeColsCostBySet(lp(), lo.num_terms(), - lo.vars().data(), lo.coefs().data())); + // Highs_changeObjectiveOffset(highs, offset); TODO offset? + std::vector objc_new(NumVars()); // dense vector to + for (auto i=lo.vars().size(); i--; ) + objc_new[lo.vars()[i]] = lo.coefs()[i]; + HIGHS_CCALL(Highs_changeColsCostByRange(lp(), 0, NumVars()-1, objc_new.data())); HIGHS_CCALL(Highs_changeObjectiveSense(lp(), - obj::Type::MAX==lo.obj_sense() ? - kHighsObjSenseMaximize : kHighsObjSenseMinimize) ); + obj::Type::MAX==lo.obj_sense() ? + kHighsObjSenseMaximize : kHighsObjSenseMinimize) ); } else { throw std::runtime_error("HighS does not support multiple objectives."); } @@ -77,26 +79,28 @@ void HighsModelAPI::SetQuadraticObjective(int iobj, const QuadraticObjective& qo } void HighsModelAPI::AddConstraint(const LinConRange& lc) { - AccConstraints.add(lc); + acc_constraints_.add(lc); } void HighsModelAPI::AddConstraint(const LinConLE& lc) { - AccConstraints.add(lc); + acc_constraints_.add(lc); } void HighsModelAPI::AddConstraint(const LinConEQ& lc) { - AccConstraints.add(lc); + acc_constraints_.add(lc); } void HighsModelAPI::AddConstraint(const LinConGE& lc) { - AccConstraints.add(lc); + acc_constraints_.add(lc); } void HighsModelAPI::FinishProblemModificationPhase() { HIGHS_CCALL(Highs_addRows(lp(), - AccConstraints.lb.size(), - AccConstraints.lb.data(), - AccConstraints.ub.data(), - AccConstraints.coeffs.size(), - AccConstraints.starts.data(), - AccConstraints.indices.data(), - AccConstraints.coeffs.data())); + acc_constraints_.lb.size(), + acc_constraints_.lb.data(), + acc_constraints_.ub.data(), + acc_constraints_.coeffs.size(), + acc_constraints_.starts.data(), + acc_constraints_.indices.data(), + acc_constraints_.coeffs.data())); + acc_constraints_ = AccConstraints(); // reinitialize accumulator for model modification } + } // namespace mp diff --git a/solvers/highsmp/highsmpmodelapi.h b/solvers/highsmp/highsmpmodelapi.h index c6315a868..dbb303379 100644 --- a/solvers/highsmp/highsmpmodelapi.h +++ b/solvers/highsmp/highsmpmodelapi.h @@ -39,7 +39,7 @@ class HighsModelAPI : USE_BASE_CONSTRAINT_HANDLERS(BaseModelAPI) - struct AccConstraints{ + struct AccConstraints { /* This is to accumulate the constraints in a format suitable for Highs_addRows(...). Adding them one by one was killing performance unacceptably. */ @@ -81,7 +81,7 @@ class HighsModelAPI : AccConstraints() { starts.push_back(0); } - } AccConstraints; + } acc_constraints_; ACCEPT_CONSTRAINT(LinConRange, Recommended, CG_Linear) void AddConstraint(const LinConRange& lc); diff --git a/solvers/visitor/visitormodelapi.h b/solvers/visitor/visitormodelapi.h index fb77cea17..33a1cb908 100644 --- a/solvers/visitor/visitormodelapi.h +++ b/solvers/visitor/visitormodelapi.h @@ -25,6 +25,8 @@ class VisitorModelAPI : /// Called before problem input. /// Model info can be used to preallocate memory. + /// @note this is called before each phase of model modification + /// which can happen during iterative solving. void InitProblemModificationPhase(const FlatModelInfo*); /// After void FinishProblemModificationPhase();