diff --git a/include/mp/flat/constr_keeper.h b/include/mp/flat/constr_keeper.h index d0f998608..e104d34f1 100644 --- a/include/mp/flat/constr_keeper.h +++ b/include/mp/flat/constr_keeper.h @@ -493,21 +493,20 @@ class ConstraintKeeper final /// Export all constraints if desired. void AddAllUnbridged(BasicFlatModelAPI& be, const std::vector* pvnam) { - int con_index=0; auto con_group = GetConstraintGroup(be); - for (const auto& cont: cons_) { - bool adding = !cont.IsBridged(); + for ( ; i_2add_next_ < cons_.size(); ++i_2add_next_) { + const auto& cont = cons_[i_2add_next_]; + bool adding = !cont.IsBridged(); // includes 'unused' if (adding) { static_cast(be).AddConstraint(cont.GetCon()); - GetConverter().GetCopyLink(). + GetConverter().GetCopyLink(). // Linking to the "final" nodes AddEntry({ - GetValueNode().Select(con_index), + GetValueNode().Select(i_2add_next_), GetConverter().GetValuePresolver().GetTargetNodes(). GetConValues()(con_group).Add() }); } - ExportConStatus(con_index, cont, pvnam, adding); - ++con_index; // increment index + ExportConStatus(i_2add_next_, cont, pvnam, adding); } } @@ -517,7 +516,9 @@ class ConstraintKeeper final std::deque cons_; int i_cvt_last_ = -1; // Last converted constraint. int n_bridged_or_unused_ = 0; // Number of converted items, - // they won't go to Backend + // they won't go to Backend. + int i_2add_next_ = 0; // Next constraint to consider + // for adding to Backend. const std::string desc_ { std::string("ConstraintKeeper< ") + Converter::GetTypeName() + ", " + diff --git a/include/mp/flat/converter_model.h b/include/mp/flat/converter_model.h index 2eb49281b..cfeacd9e5 100644 --- a/include/mp/flat/converter_model.h +++ b/include/mp/flat/converter_model.h @@ -392,12 +392,12 @@ class FlatModel this->LogConstraintGroups(backend); } - FlatModelInfo* GetModelInfoWrt() const { return pfmi_.get(); } - public: /// Model info const FlatModelInfo* GetModelInfo() const { return pfmi_.get(); } + /// Model info, writable + FlatModelInfo* GetModelInfoWrt() const { return pfmi_.get(); } /// Set given objective template diff --git a/include/mp/flat/converter_multiobj.h b/include/mp/flat/converter_multiobj.h index f5c9fb60e..41d1605c7 100644 --- a/include/mp/flat/converter_multiobj.h +++ b/include/mp/flat/converter_multiobj.h @@ -83,7 +83,7 @@ class MOManager { /// Necessary to be called. /// @note Can be called before or after unpostsolved solution. /// Should contain at least valid solve status. - void ProcessMOIterationPostsolvedSolution(const Solution& sol, int solst) { + void ProcessMOIterationPostsolvedSolution(const Solution& , int solst) { assert(sol::Status::NOT_SET != solst); assert(IsMOActive()); assert(MOManagerStatus::FINISHED != status_); @@ -176,12 +176,14 @@ class MOManager { "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(); - MPD( GetModelAPI() ).FinishProblemModificationPhase(); + MPD( FillConstraintCounters( MPD( GetModelAPI() ), *MPD( GetModelInfoWrt() ) ) ); // @todo a hack. + MPD( GetModelAPI() ).InitProblemModificationPhase( // For adding the new constraint. @todo a hack. + MPD( GetModelInfo() )); // Ideally Model would notice changes and notify + ReplaceCurrentObj(); // After allowing model modification (needed by SCIP.) + MPD( AddUnbridgedConstraintsToBackend( MPD( GetModelAPI() ), nullptr) ); + MPD( GetModelAPI() ).FinishProblemModificationPhase(); // ModelAPI automatically. return true; } @@ -194,18 +196,18 @@ class MOManager { lim += diff * (obj::MAX==obj_last.obj_sense() ? -1.0 : 1.0); if (obj_last.GetQPTerms().size()) { if (obj::MAX == obj_last.obj_sense()) - MPD( GetModelAPI() ).AddConstraint( - QuadConGE{ { obj_last.GetLinTerms(), obj_last.GetQPTerms() }, objval_last_ } ); + MPD( AddConstraint( + QuadConGE{ { obj_last.GetLinTerms(), obj_last.GetQPTerms() }, objval_last_ } ) ); else - MPD( GetModelAPI() ).AddConstraint( - QuadConLE{ { obj_last.GetLinTerms(), obj_last.GetQPTerms() }, objval_last_ } ); + MPD( AddConstraint( + QuadConLE{ { obj_last.GetLinTerms(), obj_last.GetQPTerms() }, objval_last_ } ) ); } else { if (obj::MAX == obj_last.obj_sense()) - MPD( GetModelAPI() ).AddConstraint( - LinConGE{ { obj_last.GetLinTerms() }, objval_last_ } ); + MPD( AddConstraint( + LinConGE{ { obj_last.GetLinTerms() }, objval_last_ } ) ); else - MPD( GetModelAPI() ).AddConstraint( - LinConLE{ { obj_last.GetLinTerms() }, objval_last_ } ); + MPD( AddConstraint( + LinConLE{ { obj_last.GetLinTerms() }, objval_last_ } ) ); } } diff --git a/solvers/mosek/mosekmodelapi.cc b/solvers/mosek/mosekmodelapi.cc index 1bed24698..143eda3d7 100644 --- a/solvers/mosek/mosekmodelapi.cc +++ b/solvers/mosek/mosekmodelapi.cc @@ -6,12 +6,13 @@ namespace mp { void MosekModelAPI::InitProblemModificationPhase(const FlatModelInfo* info) { - /// Preallocate algebraic constraints. + /// Preallocate algebraic constraints. /// MOSEK 10 seems to handle all algebraic constraints as 1 group. /// CG_Algebraic, etc. are the constraint group indexes /// provided in ACCEPT_CONSTRAINT macros. - MOSEK_CCALL(MSK_appendcons(lp(), - info->GetNumberOfConstraintsOfGroup(CG_Algebraic))); + auto n_alg_all = info->GetNumberOfConstraintsOfGroup(CG_Algebraic); + if (n_alg_cons_ < n_alg_all) + MOSEK_CCALL(MSK_appendcons(lp(), n_alg_all - n_alg_cons_)); } std::string& myreplace(std::string& s, const std::string& from, const std::string& to) { @@ -61,6 +62,8 @@ void MosekModelAPI::SetLinearObjective( int iobj, const LinearObjective& lo ) { if (iobj < 1) { MOSEK_CCALL(MSK_putobjsense(lp(), obj::Type::MAX == lo.obj_sense() ? MSK_OBJECTIVE_SENSE_MAXIMIZE : MSK_OBJECTIVE_SENSE_MINIMIZE)); + for (auto i=NumVars(); i--; ) + MOSEK_CCALL(MSK_putcj(lp(), i, 0.0)); for (int i = 0; i < lo.num_terms(); i++) { MOSEK_CCALL(MSK_putcj(lp(), lo.vars()[i], lo.coefs()[i])); } diff --git a/solvers/mosek/mosekmodelapi.h b/solvers/mosek/mosekmodelapi.h index 8191084d0..cd2fc2599 100644 --- a/solvers/mosek/mosekmodelapi.h +++ b/solvers/mosek/mosekmodelapi.h @@ -23,8 +23,9 @@ class MosekModelAPI : /// Class name static const char* GetTypeName() { return "MosekModelAPI"; } - /// Called before problem input - void InitProblemModificationPhase(const FlatModelInfo*); + /// Called before problem modification. + /// @param fmi: current problem information + void InitProblemModificationPhase(const FlatModelInfo* fmi); /// After void FinishProblemModificationPhase(); diff --git a/solvers/visitor/visitormodelapi.cc b/solvers/visitor/visitormodelapi.cc index c33cec6fb..d278ea5d9 100644 --- a/solvers/visitor/visitormodelapi.cc +++ b/solvers/visitor/visitormodelapi.cc @@ -8,7 +8,7 @@ void VisitorModelAPI::InitProblemModificationPhase( // Allocate storage if needed: // auto n_linear_cons = // flat_model_info->GetNumberOfConstraintsOfGroup(CG_LINEAR); - // preallocate_linear_cons( n_linear_cons ); + // reallocate_linear_cons( n_linear_cons ); } void VisitorModelAPI::AddVariables(const VarArrayDef& v) { diff --git a/solvers/visitor/visitormodelapi.h b/solvers/visitor/visitormodelapi.h index 153e26143..1904c2251 100644 --- a/solvers/visitor/visitormodelapi.h +++ b/solvers/visitor/visitormodelapi.h @@ -23,11 +23,11 @@ class VisitorModelAPI : /// If any driver options added from here void InitCustomOptions() { } - /// Called before problem input. - /// Model info can be used to preallocate memory. + /// Called before problem modification. + /// @param fmi: current problem information. /// @note this is called before each phase of model modification /// which can happen during iterative solving. - void InitProblemModificationPhase(const FlatModelInfo*); + void InitProblemModificationPhase(const FlatModelInfo* fmi); /// After void FinishProblemModificationPhase();