#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(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 threads{nThreads-1}; std::vector solutions(nThreads); tsp::Solution best; /* repeatability at loop level */ std::vector 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 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 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 auto hwGraspElsPar(tsp::Problem const& problem, RNG& rng) { std::size_t const nThreads = std::min(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 threadsA{nThreads-1}; std::vector threadsB{remain==0 ? 0 : remain-1}; std::vector solutions(nThreads+remain); /* repeatability at loop level */ std::vector 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(p, rng); }