Skip to content

Commit

Permalink
Multi-obj: refactor solve iteration loop #239
Browse files Browse the repository at this point in the history
PrepareNextIter() gets lambdas to obtain solution status and solution
  • Loading branch information
glebbelov committed May 28, 2024
1 parent fd0c34b commit 001df7d
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 58 deletions.
14 changes: 9 additions & 5 deletions include/mp/backend-std.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,16 @@ class StdBackend :

/// Our solving procedure.
virtual void RunSolveIterations() {
while (GetMM().PrepareSolveIteration()) {
auto get_stt = [this]() { // to be called before GetSolution()
auto sr = GetSolveResult();
SetStatus( sr );
return (sol::Status)sr.first;
};
auto get_sol = [this]() {
return GetSolution();
};
while (GetMM().PrepareSolveIteration(get_stt, get_sol)) {
Solve();
SetStatus( GetSolveResult() ); // before GetSolution()
sol_last_ = GetSolution(); // @todo don't need it in the last iteration
GetMM().ProcessIterationSolution(sol_last_, status_.first);
}
}

Expand Down Expand Up @@ -656,7 +661,6 @@ class StdBackend :
std::pair<int, std::string> status_ { sol::NOT_SET, "status not set" };
int kIntermSol_ = 0; // last written intermed solution index
std::pair<double, double> objIntermSol_ { -1e100, 1e100 };
Solution sol_last_;

///////////////////////// STORING SOLVER MESSAGES //////////////////////
private:
Expand Down
7 changes: 3 additions & 4 deletions include/mp/converter-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ class BasicConverter : public EnvKeeper {
virtual void ConvertModel() = 0;

/// Need and successfully prepared the next solve iteration?
virtual bool PrepareSolveIteration() = 0;

/// Process solve iteration solution
virtual void ProcessIterationSolution(const Solution& , int status) = 0;
virtual bool PrepareSolveIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol)
= 0;

/// Objective weights
virtual ArrayRef<double> GetObjWeightsAdapted() = 0;
Expand Down
13 changes: 4 additions & 9 deletions include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,19 +231,14 @@ class FlatConverter :
/// This should be used in particular with MO emulation.
/// @return true if the next solve should be executed
/// and its results passed via ProcessSolveIterationSolution().
bool PrepareNextSolveIteration() {
bool PrepareNextSolveIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol) {
if (MPCD( IsMOActive() ))
return MPD( PrepareMOIteration() );
return MPD( PrepareMOIteration(get_stt, get_sol) );
return !(n_solve_iter_++);
}

/// Process solve iteration solution.
void ProcessSolveIterationSolution(const Solution& sol, int status) {
if (MPCD( IsMOActive() ))
MPD( ProcessMOIterationPostsolvedSolution(sol, status) );
}

/// Objective weights
/// Objective weights, adapted according to obj:multi:weight
ArrayRef<double> GetObjWeightsAdapted() { return MPD( GetMOWeightsLegacy() ); }


Expand Down
66 changes: 42 additions & 24 deletions include/mp/flat/converter_multiobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,45 @@ class MOManager {
/// Prepare next multiobj iteration?
/// @note Call this before a MO iteration.
/// @return true iff the model is ready for the next iteration.
bool PrepareMOIteration() {
bool PrepareMOIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol) {
switch (status_) {
case MOManagerStatus::NOT_SET:
MP_RAISE("FlatConverter: MultiobjManager not started");
MP_RAISE("FlatConverter: MultiobjManager not set up");
case MOManagerStatus::NOT_ACTIVE:
MP_RAISE("FlatConverter: MultiobjManager not running");
case MOManagerStatus::RUNNING:
return DoPrepareNextMultiobjSolve();
return DoPrepareNextMultiobjSolve(get_stt, get_sol);
case MOManagerStatus::FINISHED:
return false;
}
return false;
}

/// Obtain and process a postsolved solution of the current iteration.
/// Can implicitly call ProcessMOIterationUnpostsolvedSolution().
/// @return (whether we should continue, solve_result).
std::pair<bool, sol::Status> ProcessMOIterationPostsolvedSolution(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol) {
auto solst = get_stt();
assert(sol::Status::NOT_SET != solst);
assert(IsMOActive());
assert(MOManagerStatus::FINISHED != status_);
if ((sol::IsProblemSolvedOrFeasible((sol::Status)solst)
// || sol::IsProblemMaybeSolved(solst) // Use this?
) && !sol::IsProblemUnbounded((sol::Status)solst) // Don't want unbounded
) { // (but LIMIT can have this undiscovered)
get_sol(); // This implicitly calls ProcessMOIterationUnpostsolvedSolution().
return { true, solst };
// We ignore the solution here - but having it provided
// guarantees that the postsolve has been run.
}
status_ = MOManagerStatus::FINISHED;
return { false, solst };
}

/// Process an unpostsolved solution of the current iteration.
/// Necessary to be called.
/// This is called from solution postsolve initiated by solution getter.
/// @note Can be called before or after the postsolved solution.
void ProcessMOIterationUnpostsolvedSolution(pre::ModelValuesDbl& sol) {
if (IsMOActive()) {
Expand All @@ -79,24 +102,6 @@ class MOManager {
}
}

/// Process a postsolved solution of the current iteration.
/// Necessary to be called.
/// @note Can be called before or after unpostsolved solution.
/// Should contain at least valid solve status.
void ProcessMOIterationPostsolvedSolution(const Solution& , int solst) {
assert(sol::Status::NOT_SET != solst);
assert(IsMOActive());
assert(MOManagerStatus::FINISHED != status_);
if ((sol::IsProblemSolvedOrFeasible((sol::Status)solst)
// || sol::IsProblemMaybeSolved(solst) // Use this?
) && !sol::IsProblemUnbounded((sol::Status)solst))
{} // continue
else
status_ = MOManagerStatus::FINISHED;
// We ignore the solution here - but having it provided
// guarantees that the postsolve has been run.
}


protected:
void SetupMultiobjEmulation() {
Expand Down Expand Up @@ -161,7 +166,8 @@ class MOManager {
}

/// Do prepare next solve
bool DoPrepareNextMultiobjSolve() {
bool DoPrepareNextMultiobjSolve(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol) {
if (++i_current_obj_ >= obj_new_.size()) {
status_ = MOManagerStatus::FINISHED;
MPD( GetEnv() ).Print(
Expand All @@ -176,8 +182,20 @@ class MOManager {
"MULTI-OBJECTIVE MODE: objective {} (out of {}) ...\n"
"==============================================================================\n\n"
, i_current_obj_+1, obj_new_.size());
if (i_current_obj_)
if (i_current_obj_) {
auto proc_sol = ProcessMOIterationPostsolvedSolution(get_stt, get_sol);
if (!proc_sol.first) {
if (MPD( GetEnv() ).verbose_mode())
MPD( GetEnv() ).Print(
"\n"
"MULTI-OBJECTIVE MODE: objective {} (out of {}):\n"
" ABORTING due to the previous iteration's solve result ({}).\n"
"==============================================================================\n\n"
, i_current_obj_+1, obj_new_.size(), proc_sol.second);
return false;
}
RestrictLastObjVal();
}
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
Expand Down
10 changes: 4 additions & 6 deletions include/mp/flat/problem_flattener.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,10 @@ class ProblemFlattener :
}

/// Need and successfully prepared the next solve iteration?
bool PrepareSolveIteration() override
{ return GetFlatCvt().PrepareNextSolveIteration(); }

/// Process solve iteration solution
void ProcessIterationSolution(const Solution& sol, int status) override
{ GetFlatCvt().ProcessSolveIterationSolution(sol, status); }
bool PrepareSolveIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol)
override
{ return GetFlatCvt().PrepareNextSolveIteration(get_stt, get_sol); }

/// Objective weights
ArrayRef<double> GetObjWeightsAdapted() override
Expand Down
9 changes: 5 additions & 4 deletions include/mp/model-mgr-base.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ class BasicModelManager {
double) = 0;

/// Need and successfully prepared the next solve iteration?
virtual bool PrepareSolveIteration() = 0;

/// Process solve iteration solution
virtual void ProcessIterationSolution(const Solution& , int status) = 0;
/// @param get_stt: solution status getter.
/// If called, then before get_sol.
/// @param get_sol: solution getter (for postsolved solution.)
virtual bool PrepareSolveIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol) = 0;

/// Objective weights in the 'legacy' format of the obj:multi:weight option
virtual ArrayRef<double> GetObjWeightsAdapted() = 0;
Expand Down
10 changes: 4 additions & 6 deletions include/mp/model-mgr-with-pb.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,10 @@ class ModelManagerWithProblemBuilder :
}

/// Need and successfully prepared the next solve iteration?
bool PrepareSolveIteration() override
{ return GetCvt().PrepareSolveIteration(); }

/// Process solve iteration solution
void ProcessIterationSolution(const Solution& sol, int status) override
{ GetCvt().ProcessIterationSolution(sol, status); }
bool PrepareSolveIteration(
std::function<sol::Status(void)> get_stt, std::function<Solution(void)> get_sol)
override
{ return GetCvt().PrepareSolveIteration(get_stt, get_sol); }

/// Objective weights
ArrayRef<double> GetObjWeightsAdapted() override
Expand Down

0 comments on commit 001df7d

Please sign in to comment.