221 lines
5.2 KiB
C++
221 lines
5.2 KiB
C++
#include "common.h"
|
|
|
|
auto hwElsGen(tsp::Solution const& solution, RNG& rng) {
|
|
return Descent{}(Move2Opt{}(solution, rng));
|
|
}
|
|
|
|
#if PARLEV==2
|
|
auto hwElsInner(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
|
std::size_t const nThreads = std::min<std::size_t>(nCore, ELS_GEN);
|
|
std::size_t const step = ELS_GEN/nThreads;
|
|
std::size_t remain = ELS_GEN - step*nThreads;
|
|
|
|
// std::cout << "LEVEL #2 : " << nCore << ";" << nThreads << ";" << step << ";" << remain << std::endl;
|
|
|
|
std::vector<std::thread> threads{nThreads-1};
|
|
std::vector<tsp::Solution> solutions(nThreads);
|
|
|
|
tsp::Solution best;
|
|
|
|
/* repeatability at loop level */
|
|
std::vector<RNG> rngs(ELS_GEN);
|
|
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
|
rngs[i].seed(rng());
|
|
/* ***** */
|
|
|
|
std::size_t start{};
|
|
|
|
for(std::size_t i{}; i < (nThreads-1); ++i) {
|
|
std::size_t offset = !!remain;
|
|
remain -= offset;
|
|
|
|
threads[i] = std::thread{
|
|
[&,start,i,step=step+offset](auto const& solution) {
|
|
tsp::Solution& s = solutions[i];
|
|
|
|
for(std::size_t j{}; j < step; ++j) {
|
|
tsp::Solution cur = hwElsGen(solution, rngs[start+j]);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
}
|
|
},
|
|
std::cref(solution)
|
|
};
|
|
|
|
start += step+offset;
|
|
}
|
|
|
|
{
|
|
tsp::Solution& s = solutions[nThreads-1];
|
|
|
|
for(std::size_t j{}; j < step; ++j) {
|
|
tsp::Solution cur = hwElsGen(solution, rngs[start+j]);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
}
|
|
}
|
|
|
|
for(auto& thread: threads) thread.join();
|
|
|
|
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
|
|
|
return best;
|
|
}
|
|
#else
|
|
auto hwElsInner(tsp::Solution const& solution, RNG& rng, std::size_t) {
|
|
tsp::Solution best;
|
|
|
|
/* repeatability at loop level */
|
|
std::vector<RNG> rngs(ELS_GEN);
|
|
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
|
rngs[i].seed(rng());
|
|
/* ***** */
|
|
|
|
if(ELS_GEN)
|
|
best = hwElsGen(solution, rngs[0]);
|
|
|
|
for(std::size_t i = 1; i < ELS_GEN; ++i) {
|
|
tsp::Solution current = hwElsGen(solution, rngs[i]);
|
|
best = selectMin(std::move(best), std::move(current));
|
|
}
|
|
|
|
return best;
|
|
}
|
|
#endif
|
|
|
|
auto hwEls(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
|
tsp::Solution best = Descent{}(solution);
|
|
|
|
for(std::size_t i = 0; i < ELS_ITER_MAX; ++i) {
|
|
tsp::Solution current = hwElsInner(best, rng, nCore);
|
|
best = selectMin(std::move(best), std::move(current));
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
auto hwGraspGen(tsp::Problem const& problem, RNG& rng, std::size_t nCore = 1) {
|
|
return hwEls(rgreedy()(problem, rng), rng, nCore);
|
|
}
|
|
|
|
/* *** */
|
|
|
|
auto hwGraspEls(tsp::Problem const& problem, RNG& rng) {
|
|
tsp::Solution best;
|
|
|
|
/* repeatability at loop level */
|
|
std::vector<RNG> rngs(GRASP_N);
|
|
for(std::size_t i = 0; i < GRASP_N; ++i)
|
|
rngs[i].seed(rng());
|
|
/* ***** */
|
|
|
|
if(GRASP_N)
|
|
best = hwGraspGen(problem, rngs[0]);
|
|
for(std::size_t i = 1; i < GRASP_N; ++i) {
|
|
tsp::Solution current = hwGraspGen(problem, rngs[i]);
|
|
best = selectMin(std::move(best), std::move(current));
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
template<std::size_t K>
|
|
auto hwGraspElsPar(tsp::Problem const& problem, RNG& rng) {
|
|
std::size_t const nThreads = std::min<std::size_t>(K, GRASP_N);
|
|
std::size_t const step = GRASP_N/nThreads;
|
|
std::size_t const remain = GRASP_N - step*nThreads;
|
|
|
|
std::size_t cores2a = K/nThreads;
|
|
std::size_t cores2b = (remain==0 ? 1 : K/remain);
|
|
|
|
// std::cout << "LEVEL #1 : " << K << ";" << nThreads << ";" << step << ";" << remain << std::endl;
|
|
|
|
tsp::Solution best;
|
|
|
|
std::vector<std::thread> threadsA{nThreads-1};
|
|
std::vector<std::thread> threadsB{remain==0 ? 0 : remain-1};
|
|
|
|
std::vector<tsp::Solution> solutions(nThreads+remain);
|
|
|
|
/* repeatability at loop level */
|
|
std::vector<RNG> rngs(GRASP_N);
|
|
for(std::size_t i = 0; i < GRASP_N; ++i)
|
|
rngs[i].seed(rng());
|
|
/* ***** */
|
|
|
|
std::size_t start{};
|
|
std::size_t i{};
|
|
|
|
/* Loop A */
|
|
for(; i < (nThreads-1); ++i) {
|
|
threadsA[i] = std::thread{
|
|
[&,start,i,cores2a](auto const& problem) {
|
|
tsp::Solution& s = solutions[i];
|
|
|
|
for(std::size_t j{}; j < step; ++j) {
|
|
tsp::Solution cur = hwGraspGen(problem, rngs[start+j],cores2a);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
}
|
|
},
|
|
std::cref(problem)
|
|
};
|
|
|
|
start += step;
|
|
}
|
|
|
|
{
|
|
tsp::Solution& s = solutions[i];
|
|
|
|
for(std::size_t j{}; j < step; ++j) {
|
|
tsp::Solution cur = hwGraspGen(problem, rngs[start+j],cores2a);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
}
|
|
|
|
start+=step;
|
|
++i;
|
|
}
|
|
|
|
for(auto& thread: threadsA) thread.join();
|
|
|
|
/* Loop B */
|
|
for(; i < nThreads+remain-1; ++i) {
|
|
threadsB[i-nThreads] = std::thread{
|
|
[&,start,i,cores2b](auto const& problem) {
|
|
tsp::Solution& s = solutions[i];
|
|
|
|
tsp::Solution cur = hwGraspGen(problem, rngs[start],cores2b);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
},
|
|
std::cref(problem)
|
|
};
|
|
|
|
++start;
|
|
}
|
|
|
|
if (remain>0)
|
|
{
|
|
tsp::Solution& s = solutions[i];
|
|
|
|
tsp::Solution cur = hwGraspGen(problem, rngs[start],cores2b);
|
|
s = selectMin(std::move(s), std::move(cur));
|
|
++start;
|
|
++i;
|
|
}
|
|
|
|
for(auto& thread: threadsB) thread.join();
|
|
|
|
/* Selection */
|
|
|
|
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
|
|
|
return best;
|
|
}
|
|
|
|
/* *** */
|
|
|
|
tsp::Solution hw_seq(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
|
return hwGraspEls(p, rng);
|
|
}
|
|
|
|
tsp::Solution hw_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
|
return hwGraspElsPar<NTHREADS>(p, rng);
|
|
}
|