Skip to content

Commit

Permalink
Tests for obj reformulations, also with .objweight
Browse files Browse the repository at this point in the history
  • Loading branch information
glebbelov committed Jul 30, 2024
1 parent 26002c4 commit 48e0d82
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 12 deletions.
9 changes: 9 additions & 0 deletions CHANGES.mp.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ Summary of recent updates to the AMPL MP Library
================================================


## unreleased
- SCIP (and any solver with linear objective
and non-linear constraints): improve reformulation
of QP objectives.
- Fix reformulation of non-linear objective expressions
for the multi-objective case (option obj:multi) when
negative objective weights are used (obj:multi:weight.)


## 20240724
- Option *acc:_all*
- Useful to disable all reformulations (acc:_all=2),
Expand Down
13 changes: 9 additions & 4 deletions include/mp/flat/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1143,11 +1143,16 @@ class FlatConverter :

GetEnv().AddOption("cvt:quadobj passquadobj",
ModelAPIAcceptsQuadObj() ?
"0/1*: Multiply out and pass quadratic objective terms to the solver, "
"vs. linear approximation."
"0/1*: Pass quadratic objective terms to the solver. "
"If the solver accepts quadratic constraints, "
"such a constraint will be created with those, "
"otherwise linearly approximated."
:
"0*/1: Multiply out and pass quadratic objective terms to the solver, "
"vs. linear approximation.",
"0*/1: Pass quadratic objective terms to the solver, "
"If the solver accepts quadratic constraints, "
"such a constraint will be created with those, "
"otherwise linearly approximated."
,
options_.passQuadObj_, 0, 1);
GetEnv().AddOption("cvt:quadcon passquadcon",
"Convenience option. "
Expand Down
13 changes: 9 additions & 4 deletions include/mp/flat/converter_multiobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ class MOManager {
std::vector<int> objpr = MPD( ReadIntSuffix( {"objpriority", suf::OBJ} ) ); // int only
objpr.resize(obj_orig.size(), 0.0); // blend objectives by default
std::vector<double> objwgt = MPD( GetMOWeightsLegacy() );
if (objwgt.empty()) {
objwgt.resize(obj_orig.size(), 1.0); // Default "intuitive" weights
FlipDiffSenseSigns(objwgt); // Backend / Emulator want "legacy"
}
std::vector<double> objtola = MPD( ReadDblSuffix( {"objabstol", suf::OBJ} ) );
objtola.resize(obj_orig.size(), 0.0);
std::vector<double> objtolr = MPD( ReadDblSuffix( {"objreltol", suf::OBJ} ) );
Expand Down Expand Up @@ -235,7 +239,7 @@ class MOManager {

/// The "intuitive" objective weights
/// @return Always a full vector (for all objs)
/// @note All these methods assume the obj list is completed
/// @note Assume the obj list is completed
ArrayRef<double> GetMOWeights() {
std::vector<double> objwgt = MPD( GetMOWeightsLegacy() );
const auto& obj_orig = MPD( get_objectives() ); // no linking
Expand All @@ -248,20 +252,21 @@ class MOManager {
}

/// @return Legacy weights (relative to the 1st obj),
/// if .objweight provided, or default
/// if .objweight provided
/// @note Assume the obj list is completed
ArrayRef<double> GetMOWeightsLegacy() {
std::vector<double> objw = MPD( ReadDblSuffix( {"objweight", suf::OBJ} ) );
const auto& obj_orig = MPD( get_objectives() ); // no linking
if (objw.empty()) {
objw.resize(obj_orig.size(), 1.0); // Default "intuitive" weights
FlipDiffSenseSigns(objw); // Backend / Emulator want "legacy"
// pass
} else if (2==MPD( GetEnv() ).multiobj_weight()) { // user gave "intuitive" values
FlipDiffSenseSigns(objw); // Backend / Emulator want "legacy"
}
return objw;
}

/// Convert between the options of obj:multi:weight
/// @note Assume the obj list is completed
void FlipDiffSenseSigns(std::vector<double>& objw) {
const auto& obj = MPD( get_objectives() );
if (obj.size() > 1) {
Expand Down
2 changes: 1 addition & 1 deletion solvers/gurobi/gurobibackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ SolutionBasis GurobiBackend::GetBasis() {
{{{ CG_Linear, std::move(constt) }}} } );
varstt = mv.GetVarValues()();
constt = mv.GetConValues()();
assert(varstt.size());
assert(varstt.size()); // not for constraints
}
return { std::move(varstt), std::move(constt) };
}
Expand Down
3 changes: 1 addition & 2 deletions solvers/mosek/mosekbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -905,8 +905,7 @@ SolutionBasis MosekBackend::GetBasis() {
{{{ CG_Algebraic, std::move(constt) }}} });
varstt = mv.GetVarValues()();
constt = mv.GetConValues()();
assert(varstt.size());
assert(constt.size());
assert(varstt.size()); // not for constraints
}
return { std::move(varstt), std::move(constt) };
}
Expand Down
2 changes: 1 addition & 1 deletion solvers/visitor/visitorbackend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ SolutionBasis VisitorBackend::GetBasis() {
{{{ CG_Linear, std::move(constt) }}} });
varstt = mv.GetVarValues()();
constt = mv.GetConValues()();
assert(varstt.size());
assert(varstt.size()); // not for constraints, can be QCP
}
return { std::move(varstt), std::move(constt) };
}
Expand Down
30 changes: 30 additions & 0 deletions test/end2end/cases/categorized/fast/multi_obj/modellist.json
Original file line number Diff line number Diff line change
Expand Up @@ -248,5 +248,35 @@
"values": {
"z": 1
}
},
{
"name" : "obj_abs_01",
"tags" : ["linear", "integer", "multiobj"],
"options": {
"ANYSOLVER_options": "multiobj=1"
},
"values": {
"_sobj[1]": 13,
"_sobj[2]": -17
}
},
{
"name" : "obj_abs_02",
"tags" : ["linear", "integer", "multiobj"],
"options": {
"ANYSOLVER_options": "multiobj=1"
},
"values": {
"_sobj[1]": 13,
"_sobj[2]": 4.333333333333333333
}
},
{
"name" : "obj_abs_02 obj:no=2",
"tags" : ["linear", "integer"],
"options": {
"ANYSOLVER_options": "obj:no=2"
},
"objective": 4.3333333333333333333
}
]
20 changes: 20 additions & 0 deletions test/end2end/cases/categorized/fast/multi_obj/obj_abs_01.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#######################################
## obj_abs_01.mod
## Test objective sense-aware reformulation
## Test .objweight in obj:multi mode
## abs()
#######################################

var x >=-2 <=5;
var y >=-12 <=3;


suffix objpriority IN;
suffix objweight IN;

## The 1st objective is dummy, to enable the multi-objective approach
minimize ObjD: 3*x - 2*y suffix objpriority 1, suffix objweight 1;
maximize Obj1: abs(x) - 2*abs(y) suffix objpriority 2, suffix objweight -2;

s.t. C1: 3*x - 2*y == 13;

20 changes: 20 additions & 0 deletions test/end2end/cases/categorized/fast/multi_obj/obj_abs_02.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#######################################
## obj_abs_02.mod
## Test objective sense-aware reformulation
## Test .objweight in obj:multi mode
## abs()
#######################################

var x >=-2 <=5;
var y >=-12 <=3;


suffix objpriority IN;
suffix objweight IN;

## The 1st objective is dummy, to enable the multi-objective approach
minimize ObjD: 3*x - 2*y suffix objpriority 1, suffix objweight -1;
maximize Obj1: abs(x) - 2*abs(y) suffix objpriority 2, suffix objweight 3;

s.t. C1: 3*x - 2*y == 13;

8 changes: 8 additions & 0 deletions test/end2end/cases/categorized/fast/qp/modellist.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@
"objective" : 0,
"tags" : ["quadratic_obj"]
},
{
"name" : "quad_obj_repeated cvt:quadobj=0",
"objective" : 0,
"tags" : ["quadratic_obj"],
"options": {
"ANYSOLVER_options": "cvt:quadobj=0"
}
},
{
"name" : "prod_bin_var_01",
"objective" : 5,
Expand Down

1 comment on commit 48e0d82

@glebbelov
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.