Skip to content

Commit 2fdfdc9

Browse files
committed
Add Sense and compare_int for objective comparison
Implementing Space::compare for an integer objective took four lines of value comparisons, against a single rel call in constrain. compare_int compares two values for a Sense, an optimization direction now shared by the kernel, MiniModel, FlatZinc, and the experimental heuristic guidance, which had its own MINIMIZE/MAXIMIZE enum.
1 parent 0f02b6d commit 2fdfdc9

10 files changed

Lines changed: 40 additions & 35 deletions

File tree

‎changelog.in‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ Add Space::compare(), which ranks two solutions without modifying them.
8484
Best-solution search uses it to choose between solutions, for example in
8585
parallel BAB, portfolios, external incumbents, and the experimental A* and
8686
CABS engines. constrain() still prunes the search. Optimization models with a
87-
custom constrain() must now also override compare(). Search
87+
custom constrain() must now also override compare(). compare_int()
88+
compares two integer objective values for a given Sense. Search
8889
engines throw Search::Incomparable when compare() reports incomparable
8990
solutions.
9091

‎examples/car-sequencing.cpp‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,8 @@ class CarSequencing : public Script {
371371

372372
/// Compare objective values
373373
virtual SpaceComparison compare(const Space& _other) const {
374-
const CarSequencing& other =
375-
dynamic_cast<const CarSequencing&>(_other);
376-
if (nstall.val() < other.nstall.val())
377-
return SC_BETTER;
378-
if (nstall.val() > other.nstall.val())
379-
return SC_WORSE;
380-
return SC_EQUIVALENT;
374+
const CarSequencing& other = static_cast<const CarSequencing&>(_other);
375+
return compare_int(nstall.val(), other.nstall.val(), Sense::minimize);
381376
}
382377

383378
/// Print solution

‎examples/fifteen-puzzle.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ run(PuzzleOptions& opt) {
418418
case PuzzleOptions::SEARCH_ASTAR:
419419
case PuzzleOptions::SEARCH_CABS:
420420
{
421-
Search::HeuristicGuidance guidance(Search::HeuristicGuidance::MINIMIZE,
421+
Search::HeuristicGuidance guidance(Sense::minimize,
422422
[](const Space& home) -> std::int64_t {
423423
return static_cast<const Model&>(home).bound();
424424
});

‎examples/tsptw.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ main(int argc, char* argv[]) {
381381
case TSPTW::SEARCH_ASTAR:
382382
case TSPTW::SEARCH_CABS:
383383
{
384-
Search::HeuristicGuidance g(Search::HeuristicGuidance::MINIMIZE,
384+
Search::HeuristicGuidance g(Sense::minimize,
385385
[](const Space& s) -> std::int64_t {
386386
return static_cast<const TSPTW&>(s).cost().min();
387387
});

‎gecode/flatzinc/flatzinc.cpp‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2092,10 +2092,8 @@ namespace Gecode { namespace FlatZinc {
20922092
((_method != MIN) && (_method != MAX)))
20932093
throw DynamicCastFailed("FlatZincSpace::compare");
20942094
if (_optVarIsInt) {
2095-
int a=iv[_optVar].val(), b=other->iv[other->_optVar].val();
2096-
if (a == b)
2097-
return SC_EQUIVALENT;
2098-
return ((a < b) == (_method == MIN)) ? SC_BETTER : SC_WORSE;
2095+
return compare_int(iv[_optVar].val(),other->iv[other->_optVar].val(),
2096+
(_method == MIN) ? Sense::minimize : Sense::maximize);
20992097
}
21002098
#ifdef GECODE_HAS_FLOAT_VARS
21012099
if (step != other->step)

‎gecode/kernel/core.hpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ namespace Gecode {
6161
SC_INCOMPARABLE ///< Neither objective dominates the other
6262
};
6363

64+
/// Optimization direction
65+
enum class Sense {
66+
minimize, ///< Smaller objective values are better
67+
maximize ///< Larger objective values are better
68+
};
69+
70+
/// Compare objective value \a x with \a y for direction \a s
71+
forceinline SpaceComparison
72+
compare_int(int x, int y, Sense s) {
73+
if (x == y)
74+
return SC_EQUIVALENT;
75+
return ((x < y) == (s == Sense::minimize)) ? SC_BETTER : SC_WORSE;
76+
}
77+
6478
class Space;
6579

6680
/**

‎gecode/minimodel/optimize.cpp‎

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,6 @@
3535

3636
namespace Gecode {
3737

38-
static SpaceComparison
39-
compare_int(int x, int y, bool minimize) {
40-
if (x == y)
41-
return SC_EQUIVALENT;
42-
return ((x < y) == minimize) ? SC_BETTER : SC_WORSE;
43-
}
44-
4538
void
4639
IntMinimizeSpace::constrain(const Space& _best) {
4740
const IntMinimizeSpace* best =
@@ -56,7 +49,7 @@ namespace Gecode {
5649
const IntMinimizeSpace* s = dynamic_cast<const IntMinimizeSpace*>(&other);
5750
if (s == nullptr)
5851
throw DynamicCastFailed("IntMinimizeSpace::compare");
59-
return compare_int(cost().val(),s->cost().val(),true);
52+
return compare_int(cost().val(),s->cost().val(),Sense::minimize);
6053
}
6154

6255

@@ -74,7 +67,7 @@ namespace Gecode {
7467
const IntMaximizeSpace* s = dynamic_cast<const IntMaximizeSpace*>(&other);
7568
if (s == nullptr)
7669
throw DynamicCastFailed("IntMaximizeSpace::compare");
77-
return compare_int(cost().val(),s->cost().val(),false);
70+
return compare_int(cost().val(),s->cost().val(),Sense::maximize);
7871
}
7972

8073

@@ -103,7 +96,7 @@ namespace Gecode {
10396
for (int i=0; i<a.size(); i++) {
10497
int av=a[i].val(), bv=b[i].val();
10598
if (av != bv)
106-
return compare_int(av,bv,true);
99+
return compare_int(av,bv,Sense::minimize);
107100
}
108101
return SC_EQUIVALENT;
109102
}
@@ -133,7 +126,7 @@ namespace Gecode {
133126
for (int i=0; i<a.size(); i++) {
134127
int av=a[i].val(), bv=b[i].val();
135128
if (av != bv)
136-
return compare_int(av,bv,false);
129+
return compare_int(av,bv,Sense::maximize);
137130
}
138131
return SC_EQUIVALENT;
139132
}

‎gecode/search.hh‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,8 +1260,6 @@ namespace Gecode { namespace Search {
12601260
*/
12611261
class HeuristicGuidance {
12621262
public:
1263-
/// Objective direction
1264-
enum Sense { MINIMIZE, MAXIMIZE };
12651263
/// Function evaluating a stable space
12661264
typedef std::function<std::int64_t(const Space&)> Evaluate;
12671265
/// Objective direction

‎gecode/search/heuristic.hh‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ namespace Gecode { namespace Search {
4646

4747
/// Whether bound \a a is better than bound \a b for objective direction \a s
4848
forceinline bool
49-
better(HeuristicGuidance::Sense s, std::int64_t a, std::int64_t b) {
50-
return (s == HeuristicGuidance::MINIMIZE) ? (a < b) : (a > b);
49+
better(Sense s, std::int64_t a, std::int64_t b) {
50+
return (s == Sense::minimize) ? (a < b) : (a > b);
5151
}
5252

5353
/// Open node of a heuristic search engine
@@ -71,7 +71,7 @@ namespace Gecode { namespace Search {
7171
class Priority {
7272
public:
7373
/// Objective direction
74-
HeuristicGuidance::Sense sense;
74+
Sense sense;
7575
/// Whether to order by rank only (CABS with rank)
7676
bool rank_only;
7777
/// Test whether \a a is preferred to \a b
@@ -93,15 +93,15 @@ namespace Gecode { namespace Search {
9393
class Incumbent {
9494
public:
9595
/// Objective direction
96-
HeuristicGuidance::Sense sense;
96+
Sense sense;
9797
/// The solution (if any)
9898
std::unique_ptr<Space> space;
9999
/// Its objective value
100100
std::int64_t bound;
101101
/// Incremented for every new incumbent
102102
unsigned long long int revision;
103103
/// Initialize without incumbent
104-
Incumbent(HeuristicGuidance::Sense s)
104+
Incumbent(Sense s)
105105
: sense(s), bound(0), revision(0) {}
106106
/// Whether a node with bound \a b can improve the incumbent
107107
bool improves(std::int64_t b) const {

‎test/search.cpp‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ namespace Test {
162162
static Gecode::Search::HeuristicGuidance
163163
guidance(bool max, bool ranked, bool dominance, bool keyed) {
164164
using Gecode::Search::HeuristicGuidance;
165-
HeuristicGuidance g(max ? HeuristicGuidance::MAXIMIZE :
166-
HeuristicGuidance::MINIMIZE,
165+
HeuristicGuidance g(max ? Sense::maximize : Sense::minimize,
167166
[](const Space& s) -> std::int64_t {
168167
const TreeSpace& t = static_cast<const TreeSpace&>(s);
169168
return t.maximize ? -t.node().bound : t.node().bound;
@@ -1380,7 +1379,7 @@ namespace Test {
13801379
if (!rejects_incomparable(Gecode::Search::babengine(&im,Gecode::Search::Options())))
13811380
return false;
13821381
#ifdef GECODE_HAS_EXPERIMENTAL
1383-
Gecode::Search::HeuristicGuidance g(Gecode::Search::HeuristicGuidance::MINIMIZE,
1382+
Gecode::Search::HeuristicGuidance g(Gecode::Sense::minimize,
13841383
[](const Space& s) -> std::int64_t {
13851384
return static_cast<const ExternalObjective&>(s).x.min();
13861385
});
@@ -1841,6 +1840,13 @@ namespace Test {
18411840
if ((high.compare(low) != SC_BETTER) ||
18421841
(low.compare(high) != SC_WORSE))
18431842
return false;
1843+
if ((compare_int(1,2,Sense::minimize) != SC_BETTER) ||
1844+
(compare_int(2,1,Sense::minimize) != SC_WORSE) ||
1845+
(compare_int(1,1,Sense::minimize) != SC_EQUIVALENT) ||
1846+
(compare_int(2,1,Sense::maximize) != SC_BETTER) ||
1847+
(compare_int(1,2,Sense::maximize) != SC_WORSE) ||
1848+
(compare_int(1,1,Sense::maximize) != SC_EQUIVALENT))
1849+
return false;
18441850
LexObjective lp(1,0,2), lq(2,0,2);
18451851
if ((lp.compare(lq) != SC_BETTER) ||
18461852
(lq.compare(lp) != SC_WORSE))

0 commit comments

Comments
 (0)