Skip to content

Commit a3a877f

Browse files
committed
Report always the last successful colouring (if found any)
1 parent d3487b7 commit a3a877f

File tree

6 files changed

+85
-34
lines changed

6 files changed

+85
-34
lines changed

framework/colouring/graph_colouring.cpp

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ namespace graph_colouring {
126126
boost::lockfree::queue<WorkingPackage> &workQueue,
127127
boost::lockfree::queue<MasterPackage> &masterQueue,
128128
std::vector<Colouring> &population,
129+
std::vector<Colouring> &localBestColourings,
129130
std::vector<std::atomic<bool>> &lock,
130131
std::atomic<ColorCount> &target_k,
131132
std::atomic<bool> &terminated) {
@@ -202,6 +203,8 @@ namespace graph_colouring {
202203
if (strategy.isSolution(G, target_k, result) && last_reported_k > target_k) {
203204
last_reported_k = colorCount(result);
204205
masterQueue.push({last_reported_k, wp.strategyId});
206+
size_t threadCount = localBestColourings.size() / strategies.size();
207+
localBestColourings[wp.strategyId * threadCount + threadId] = result;
205208
}
206209
}
207210
std::this_thread::yield();
@@ -227,6 +230,7 @@ namespace graph_colouring {
227230
}
228231

229232
std::vector<Colouring> population(strategies.size() * populationSize);
233+
std::vector<Colouring> localBestColourings(strategies.size() * threadCount);
230234
//lock[i] = true -> i-th individual is free for mating
231235
std::vector<std::atomic<bool>> lock(strategies.size() * populationSize);
232236
std::vector<ColouringStrategyContext> context(strategies.size());
@@ -254,6 +258,7 @@ namespace graph_colouring {
254258
std::ref(workQueue),
255259
std::ref(masterQueue),
256260
std::ref(population),
261+
std::ref(localBestColourings),
257262
std::ref(lock),
258263
std::ref(target_k),
259264
std::ref(terminated));
@@ -306,14 +311,34 @@ namespace graph_colouring {
306311

307312
std::vector<ColouringResult> bestResults(strategies.size());
308313
for (size_t strategyId = 0; strategyId < strategies.size(); strategyId++) {
309-
auto best = strategyId;
310-
for (int i = 0; i < populationSize; i++) {
311-
auto nextTry = strategyId * populationSize + i;
312-
if (strategies[strategyId]->compare(G, population[best], population[nextTry])) {
313-
best = nextTry;
314+
Colouring *bestColouring = nullptr;
315+
for (size_t i = 0; i < threadCount; i++) {
316+
auto &localBestColouring = localBestColourings[strategyId * threadCount + i];
317+
if (localBestColouring.empty()) {
318+
continue;
319+
}
320+
if (bestColouring == nullptr) {
321+
bestColouring = &localBestColouring;
322+
continue;
323+
}
324+
bestColouring = colorCount(*bestColouring) > colorCount(localBestColouring)
325+
? &localBestColouring : bestColouring;
326+
}
327+
328+
bool foundBestColourings = bestColouring != nullptr;
329+
330+
if (!foundBestColourings) {
331+
for (size_t i = 0; i < populationSize; i++) {
332+
auto nextTry = strategyId * populationSize + i;
333+
if (bestColouring == nullptr) {
334+
bestColouring = &population[nextTry];
335+
continue;
336+
}
337+
bestColouring = strategies[strategyId]->compare(G, *bestColouring, population[nextTry])
338+
? &population[nextTry] : bestColouring;
314339
}
315340
}
316-
bestResults[strategyId] = {population[best], nullptr};
341+
bestResults[strategyId] = {*bestColouring, foundBestColourings};
317342
}
318343
return bestResults;
319344
}

framework/colouring/graph_colouring.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,15 @@ namespace graph_colouring {
170170
virtual bool isFixedKStrategy() const = 0;
171171

172172
/**
173-
* Used to compare the scoring of two coloring.
173+
* Used to compare the scorings of two colorings within a strategy-specific population.
174+
* It is guaranteed that the compared instances resulted from the same initialization phase,
175+
* which may be important in fixed-k strategies.
176+
* The executing parallel colouring algorithm will always prefer the colourings with the smallest
177+
* amount of used colours for the final reporting.
174178
* @param G the target graph
175179
* @param a the first coloring
176180
* @param b the second coloring
177-
* @return True if coloring \p has a lesser score compared to coloring \p b
181+
* @return True if coloring \p a has a lesser score compared to coloring \p b
178182
*/
179183
virtual bool compare(const graph_access &G,
180184
const Colouring &a,
@@ -223,13 +227,13 @@ namespace graph_colouring {
223227
};
224228

225229
/**
226-
* @brief Represents a single result from coloringAlgorithm()
230+
* @brief Represents the best colouring for each strategy
227231
*/
228232
struct ColouringResult {
229233
/**< The best configuration */
230234
Colouring s;
231-
/**< The algorithm category used to retrieve the corresponding category */
232-
std::unique_ptr<ColouringStrategy> strategy;
235+
/**< True if no correct colouring could be found for the particular configuration */
236+
bool isValid;
233237
};
234238

235239
class ColouringAlgorithm {

framework/colouring/hca.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
namespace graph_colouring {
88

9-
Colouring hybridColouringAlgorithm(
9+
ColouringResult hybridColouringAlgorithm(
1010
const graph_access &G,
1111
const ColorCount k,
1212
const size_t population_size,
@@ -20,17 +20,17 @@ namespace graph_colouring {
2020
std::vector<std::unique_ptr<ColouringStrategy>> strategies;
2121
strategies.emplace_back(new FixedKColouringStrategy());
2222
strategies[0]->initOperators.emplace_back([](const graph_access &graph,
23-
const ColorCount colors) {
23+
const ColorCount colors) {
2424
return graph_colouring::initByGreedySaturation(graph, colors);
2525

2626
});
2727
strategies[0]->crossoverOperators.emplace_back([](const Colouring &s1,
28-
const Colouring &s2,
29-
const graph_access &graph) {
28+
const Colouring &s2,
29+
const graph_access &graph) {
3030
return graph_colouring::gpxCrossover(s1, s2);
3131
});
3232
strategies[0]->lsOperators.emplace_back([L, A, alpha](const Colouring &s,
33-
const graph_access &graph) {
33+
const graph_access &graph) {
3434
return graph_colouring::tabuSearchOperator(s, graph, L, A, alpha);
3535
});
3636

@@ -40,6 +40,6 @@ namespace graph_colouring {
4040
population_size,
4141
maxItr,
4242
threadCount,
43-
outputStream)[0].s;
43+
outputStream)[0];
4444
}
4545
}

framework/colouring/hca.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ namespace graph_colouring {
2121
* @param outputStream if not null, it will be used to report recently found colourings
2222
* @return the best found colouring
2323
*/
24-
Colouring hybridColouringAlgorithm(const graph_access &G,
25-
ColorCount k,
26-
size_t populationSize,
27-
size_t maxItr,
28-
size_t L,
29-
size_t A,
30-
double alpha,
31-
size_t threadCount = std::thread::hardware_concurrency(),
32-
std::ostream *outputStream = nullptr);
24+
ColouringResult hybridColouringAlgorithm(const graph_access &G,
25+
ColorCount k,
26+
size_t populationSize,
27+
size_t maxItr,
28+
size_t L,
29+
size_t A,
30+
double alpha,
31+
size_t threadCount = std::thread::hardware_concurrency(),
32+
std::ostream *outputStream = nullptr);
3333

3434
}

micro_benchs/colouring/hca_mb.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,24 @@ void BM_hca(benchmark::State &state,
2222
auto A = size_t(state.range(6));
2323
const double alpha = double(state.range(7)) / 10;
2424
auto result = hybridColouringAlgorithm(G, k, population_size, maxItr, L, A, alpha, threadCount);
25-
auto result_k = graph_colouring::colorCount(result);
25+
auto result_k = graph_colouring::colorCount(result.s);
2626
if (result_k > min_k) {
2727
std::cerr << "Should return a colouring with k = "
2828
<< min_k << " (is actually " << result_k << ")\n";
2929
}
30+
if (!result.isValid) {
31+
std::cerr << "Should return a valid colouring\n";
32+
}
3033
}
3134
}
3235

3336
BENCHMARK_CAPTURE(BM_hca, miles250,
3437
"../../input/miles250-sorted.graph")
3538
->Unit(benchmark::kMillisecond)
36-
->Args({1, 7, 9, 100, 20, 5, 2, 6})
37-
->Args({2, 7, 9, 100, 20, 5, 2, 6})
38-
->Args({1, 7, 9, 1000, 20, 5, 2, 6})
39-
->Args({2, 7, 9, 1000, 20, 5, 2, 6});
39+
->Args({1, 8, 9, 100, 20, 5, 2, 6})
40+
->Args({2, 8, 9, 100, 20, 5, 2, 6})
41+
->Args({1, 8, 9, 1000, 20, 5, 2, 6})
42+
->Args({2, 8, 9, 1000, 20, 5, 2, 6});
4043

4144
/*
4245
BENCHMARK_CAPTURE(BM_hca, DSJC250_5,

tests/framework/colouring/hca_test.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,26 @@ TEST(HybridColouringAlgorithm, miles250_Graph_k7) {
2424
const size_t k = 7;
2525
const size_t population_size = 20;
2626
const size_t maxItr = 20;
27-
auto s_best = graph_colouring::hybridColouringAlgorithm(G, k, population_size, maxItr, L, A, alpha);
28-
EXPECT_EQ(graph_colouring::colorCount(s_best), 7);
29-
EXPECT_TRUE(graph_colouring::numberOfConflictingEdges(G, s_best) <= 4);
27+
auto best = hybridColouringAlgorithm(G, k, population_size, maxItr, L, A, alpha);
28+
EXPECT_EQ(colorCount(best.s), 7);
29+
EXPECT_FALSE(best.isValid);
30+
EXPECT_TRUE(numberOfConflictingEdges(G, best.s) <= 4);
31+
}
32+
33+
34+
TEST(HybridColouringAlgorithm, miles250_Graph_k8) {
35+
graph_access G;
36+
std::string graph_filename = "../../input/miles250-sorted.graph";
37+
graph_io::readGraphWeighted(G, graph_filename);
38+
39+
const size_t L = 5;
40+
const size_t A = 2;
41+
const double alpha = 0.6;
42+
const size_t k = 8;
43+
const size_t population_size = 20;
44+
const size_t maxItr = 20;
45+
auto best = hybridColouringAlgorithm(G, k, population_size, maxItr, L, A, alpha);
46+
EXPECT_EQ(colorCount(best.s), 8);
47+
EXPECT_TRUE(best.isValid);
48+
EXPECT_EQ(numberOfConflictingEdges(G, best.s), 0);
3049
}

0 commit comments

Comments
 (0)