Skip to content

Commit 063687c

Browse files
committed
obj:multi:weight: intuitive objective weights #240
1 parent c73901b commit 063687c

File tree

12 files changed

+82
-8
lines changed

12 files changed

+82
-8
lines changed

include/mp/backend-std.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ class StdBackend :
116116
virtual void ObjPriorities(ArrayRef<int>)
117117
{ MP_UNSUPPORTED("Backend::ObjPriorities"); }
118118
/// Placeholder: set objective weights.
119-
/// Presolve the values if needed
119+
/// Presolve the values if needed.
120+
/// @note The weights are provided in the format common for many solver APIs,
121+
/// corresponding to the legacy setting of the option obj:multi:weight.
120122
virtual void ObjWeights(ArrayRef<double>) { }
121123
/// Placeholder: set objective abs tol
122124
/// Presolve the values if needed
@@ -290,7 +292,7 @@ class StdBackend :
290292
if (multiobj() && multiobj_has_native()) {
291293
if (auto suf = ReadSuffix(suf_objpriority))
292294
ObjPriorities( suf );
293-
if (auto suf = ReadSuffix(suf_objweight))
295+
if (auto suf = GetMM().GetObjWeightsAdapted())
294296
ObjWeights( suf );
295297
if (auto suf = ReadSuffix(suf_objabstol))
296298
ObjAbsTol( suf );
@@ -957,7 +959,6 @@ class StdBackend :
957959
//////////////////////////////////////////////////////////////////////////////
958960
private:
959961
const SuffixDef<int> suf_objpriority = { "objpriority", suf::OBJ | suf::INPUT };
960-
const SuffixDef<double> suf_objweight = { "objweight", suf::OBJ | suf::INPUT };
961962
const SuffixDef<double> suf_objabstol = { "objabstol", suf::OBJ | suf::INPUT };
962963
const SuffixDef<double> suf_objreltol = { "objreltol", suf::OBJ | suf::INPUT };
963964

include/mp/converter-base.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ class BasicConverter : public EnvKeeper {
3838
/// Process solve iteration solution
3939
virtual void ProcessIterationSolution(const Solution& , int status) = 0;
4040

41+
/// Objective weights
42+
virtual ArrayRef<double> GetObjWeightsAdapted() = 0;
43+
4144
/// Fill model traits
4245
virtual void FillModelTraits(AMPLS_ModelTraits& ) = 0;
4346

include/mp/flat/converter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ class FlatConverter :
243243
MPD( ProcessMOIterationPostsolvedSolution(sol, status) );
244244
}
245245

246+
/// Objective weights
247+
ArrayRef<double> GetObjWeightsAdapted() { return MPD( GetMOWeightsLegacy() ); }
248+
246249

247250
protected:
248251
//////////////////////////// CUSTOM CONSTRAINTS CONVERSION ////////////////////////////

include/mp/flat/converter_multiobj.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,11 @@ class MOManager {
108108
///////////////// Read / set default suffixes ///////////////////
109109
std::vector<double> objpr = MPD( ReadDblSuffix( {"objpriority", suf::OBJ} ) );
110110
objpr.resize(obj_orig.size(), 0.0); // blend objectives by default
111-
std::vector<double> objwgt = MPD( ReadDblSuffix( {"objweight", suf::OBJ} ) );
112-
objwgt.resize(obj_orig.size(), 1.0);
111+
std::vector<double> objwgt = MPD( GetMOWeightsLegacy() );
112+
if (objwgt.empty()) {
113+
objwgt.resize(obj_orig.size(), 1.0); // Default "intuitive" weights
114+
FlipDiffSenseSigns(objwgt); // We handle "legacy" format below
115+
}
113116
std::vector<double> objtola = MPD( ReadDblSuffix( {"objabstol", suf::OBJ} ) );
114117
objtola.resize(obj_orig.size(), 0.0);
115118
std::vector<double> objtolr = MPD( ReadDblSuffix( {"objreltol", suf::OBJ} ) );
@@ -124,6 +127,7 @@ class MOManager {
124127
for (const auto& pr_level: pr_map) {
125128
const auto& i0_vec = pr_level.second;
126129
obj_new_.push_back(obj_orig.at(i0_vec.front()));
130+
obj_new_.back().set_sense(obj_orig.front().obj_sense()); // "Legacy" obj:multi:weight
127131
obj_new_.back().GetLinTerms() *= objwgt.at(i0_vec.front()); // Use weight
128132
obj_new_.back().GetQPTerms() *= objwgt.at(i0_vec.front());
129133
obj_new_tola_.push_back(objtola.at(i0_vec.front()));
@@ -210,6 +214,21 @@ class MOManager {
210214
MPD( SetObjectiveTo( MPD(GetModelAPI()), 0, obj_new_[i_current_obj_]) );
211215
}
212216

217+
ArrayRef<double> GetMOWeightsLegacy() {
218+
std::vector<double> objw = MPD( ReadDblSuffix( {"objweight", suf::OBJ} ) );
219+
if (objw.size() && 2==MPD( GetEnv() ).multiobj_weight()) { // user wants "intuitive"
220+
FlipDiffSenseSigns(objw); // Backend / Emulator want "legacy"
221+
}
222+
return objw;
223+
}
224+
225+
/// Convert between the options of obj:multi:weight
226+
void FlipDiffSenseSigns(std::vector<double>& objw) {
227+
const auto& obj = MPD( get_objectives() );
228+
for (auto i=obj.size(); --i; ) // forall i>1
229+
if (obj[i].obj_sense() != obj.front().obj_sense())
230+
objw[i] = -objw[i];
231+
}
213232

214233
private:
215234
MOManagerStatus status_ {MOManagerStatus::NOT_SET};

include/mp/flat/obj_std.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class LinearObjective {
2626
name_(std::move(nm)){ }
2727
/// Get sense
2828
obj::Type obj_sense() const { return sense_; }
29+
/// Set sense
30+
void set_sense(obj::Type s) { sense_ = s; }
2931
/// Get lin terms, const
3032
const LinTerms& GetLinTerms() const { return lt_; }
3133
/// Get lin terms

include/mp/flat/problem_flattener.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class ProblemFlattener :
134134
void ProcessIterationSolution(const Solution& sol, int status) override
135135
{ GetFlatCvt().ProcessSolveIterationSolution(sol, status); }
136136

137+
/// Objective weights
138+
ArrayRef<double> GetObjWeightsAdapted() override
139+
{ return GetFlatCvt().GetObjWeightsAdapted(); }
140+
137141

138142
/// Fill model traits
139143
void FillModelTraits(AMPLS_ModelTraits& mt) override {

include/mp/model-mgr-base.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class BasicModelManager {
7676
/// Process solve iteration solution
7777
virtual void ProcessIterationSolution(const Solution& , int status) = 0;
7878

79+
/// Objective weights in the 'legacy' format of the obj:multi:weight option
80+
virtual ArrayRef<double> GetObjWeightsAdapted() = 0;
81+
7982
/// Integrality flags of the variables in the original instance.
8083
/// Used for solution rounding
8184
virtual const std::vector<bool>& IsVarInt() const = 0;

include/mp/model-mgr-with-pb.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ class ModelManagerWithProblemBuilder :
294294
void ProcessIterationSolution(const Solution& sol, int status) override
295295
{ GetCvt().ProcessIterationSolution(sol, status); }
296296

297+
/// Objective weights
298+
ArrayRef<double> GetObjWeightsAdapted() override
299+
{ return GetCvt().GetObjWeightsAdapted(); }
300+
297301

298302
const std::vector<bool>& IsVarInt() const override {
299303
return GetModel().IsVarInt();

include/mp/solver-base.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,9 @@ class BasicSolver : private ErrorHandler,
318318
/// Whether the solver natively supports multiobj
319319
bool multiobj_has_native() const { return multiobj_has_native_; }
320320

321+
/// Option obj:multi:weight
322+
int multiobj_weight() const { return multiobj_weight_; }
323+
321324
/// >0 if the timing is enabled
322325
int timing() const { return timing_; }
323326

@@ -611,6 +614,7 @@ class BasicSolver : private ErrorHandler,
611614

612615
bool multiobj_ {false};
613616
bool multiobj_has_native_ {false};
617+
int multiobj_weight_ {2};
614618

615619
bool has_errors_ {false};
616620
OutputHandler *output_handler_ {this};

solvers/visitor/visitorbackend.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class VisitorBackend :
5454
/////////////// OPTIONAL STANDARD FEATURES /////////////////
5555
////////////////////////////////////////////////////////////
5656
// Use this section to declare and implement some standard features
57-
// that may or may not need additional functions.
57+
// that may or may not need additional functions.
58+
// For a full list of features possible,
59+
// grep "STD_FEATURE".
5860
USING_STD_FEATURES;
5961

6062
/**

0 commit comments

Comments
 (0)