thesis version
This commit is contained in:
106
bench/graspels/bad_graspels.h
Normal file
106
bench/graspels/bad_graspels.h
Normal file
@ -0,0 +1,106 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_BAD_GRASPELS_H
|
||||
#define ROSA_BENCH_GRASPELS_BAD_GRASPELS_H
|
||||
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
namespace rosa {
|
||||
|
||||
/* GRASP
|
||||
* loop
|
||||
* * s = init()
|
||||
* * s = ls(s)
|
||||
* * best = select(s, best)
|
||||
* ----
|
||||
* return best
|
||||
*/
|
||||
template<typename Init, typename LS, typename Select>
|
||||
using SkelNRGraspStructure =
|
||||
alsk::S<alsk::FarmSel,
|
||||
alsk::S<alsk::Serial, Init, LS>,
|
||||
Select
|
||||
>;
|
||||
|
||||
template<typename Problem, typename Solution, typename RNG>
|
||||
using SkelNRGraspLinks =
|
||||
alsk::L<alsk::FarmSel, Solution(Problem const&, RNG&),
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::R<0> const&, alsk::arg::P<1>)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>;
|
||||
|
||||
/* *** */
|
||||
|
||||
template<
|
||||
typename Problem, typename Solution, typename RNG,
|
||||
typename Init, typename LS, typename Select
|
||||
>
|
||||
using SkelNRGrasp = alsk::BuildSkeleton<SkelNRGraspStructure, SkelNRGraspLinks>::skeleton<
|
||||
tmp::Pack<Init, LS, Select>,
|
||||
tmp::Pack<Problem, Solution, RNG>
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
namespace rosa {
|
||||
|
||||
/* ELS
|
||||
* best = ls(s) -- SEls
|
||||
* loop -- SElsOuterLoop
|
||||
* * loop -- SElsInnerLoop
|
||||
* * * s = mutate(best) -- SElsGen
|
||||
* * * s = ls(s)
|
||||
* * * ibest = select(s, ibest)
|
||||
* * ----
|
||||
* * best = select(s, best) // with acceptation criteria?
|
||||
* ----
|
||||
* return best
|
||||
*/
|
||||
template<
|
||||
typename InitLS, typename Mutate, typename LS,
|
||||
typename InnerSelect, typename OuterSelect
|
||||
>
|
||||
using SkelNRElsStruct =
|
||||
alsk::S<alsk::Serial,
|
||||
InitLS,
|
||||
alsk::S<alsk::IterSel,
|
||||
alsk::S<alsk::FarmSel,
|
||||
alsk::S<alsk::Serial,
|
||||
Mutate, LS
|
||||
>,
|
||||
InnerSelect
|
||||
>,
|
||||
OuterSelect
|
||||
>
|
||||
>;
|
||||
|
||||
template<typename Solution, typename RNG>
|
||||
using SkelNRElsLinks =
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(Solution const&, RNG&),
|
||||
Solution(alsk::arg::P<0>),
|
||||
alsk::L<alsk::IterSel, Solution(alsk::arg::R<0> const&, alsk::arg::P<1>),
|
||||
alsk::L<alsk::FarmSel, Solution(Solution const&, alsk::arg::P<1>),
|
||||
alsk::L<alsk::Serial, alsk::arg::R<1>(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::P<0>, alsk::arg::P<1>),
|
||||
Solution(alsk::arg::R<0> const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>,
|
||||
Solution(Solution const&, Solution const&)
|
||||
>
|
||||
>;
|
||||
|
||||
template<
|
||||
typename Solution, typename RNG,
|
||||
typename InitLS, typename Mutate, typename LS,
|
||||
typename InnerSelect, typename OuterSelect = InnerSelect
|
||||
>
|
||||
using SkelNREls = alsk::BuildSkeleton<SkelNRElsStruct, SkelNRElsLinks>::skeleton<
|
||||
tmp::Pack<InitLS, Mutate, LS, InnerSelect, OuterSelect>,
|
||||
tmp::Pack<Solution, RNG>
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
86
bench/graspels/common.h
Normal file
86
bench/graspels/common.h
Normal file
@ -0,0 +1,86 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_COMMON_H
|
||||
#define ROSA_BENCH_GRASPELS_COMMON_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <thread>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <alsk/alsk.h>
|
||||
|
||||
#include <muscles/descent.h>
|
||||
#include <muscles/move2opt.h>
|
||||
#include <muscles/rgreedy.h>
|
||||
|
||||
#include <rosa/els.h>
|
||||
#include <rosa/grasp.h>
|
||||
|
||||
#include <tsp/solution.h>
|
||||
#include <tsp/problem.h>
|
||||
#include <tsp/tsp.h>
|
||||
|
||||
#ifndef DATA_FILE
|
||||
#define DATA_FILE "../data/qa194"
|
||||
#endif
|
||||
#ifndef GRASP_N
|
||||
#define GRASP_N 2
|
||||
#endif
|
||||
#ifndef ELS_ITER_MAX
|
||||
#define ELS_ITER_MAX 20
|
||||
#endif
|
||||
#ifndef ELS_GEN
|
||||
#define ELS_GEN 10
|
||||
#endif
|
||||
#ifndef FUNC
|
||||
#define FUNC none
|
||||
#endif
|
||||
#ifndef NTHREADS
|
||||
#define NTHREADS 1
|
||||
#endif
|
||||
#ifndef SEED
|
||||
#define SEED std::mt19937::default_seed
|
||||
#endif
|
||||
|
||||
#define STR_(A) #A
|
||||
#define STR(A) STR_(A)
|
||||
|
||||
/* repeatable* */
|
||||
#define REPRODUCIBLE
|
||||
|
||||
using RNG = std::mt19937;
|
||||
|
||||
struct Arguments {
|
||||
std::mt19937::result_type seed;
|
||||
};
|
||||
|
||||
inline tsp::Solution selectMin(tsp::Solution const& a, tsp::Solution const& b) { return a<b? a:b; }
|
||||
inline auto rgreedy() { return RGreedy<tsp::Solution>{2}; }
|
||||
|
||||
inline double tvdiff(struct timeval& b, struct timeval& e) {
|
||||
return (e.tv_sec - b.tv_sec) + (e.tv_usec - b.tv_usec) / 1e6;
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
void timeit(int who, std::string const& prefix, F&& f, Args&&... args) {
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
|
||||
struct rusage b, e;
|
||||
|
||||
auto tp0 = Clock::now();
|
||||
getrusage(who, &b);
|
||||
std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
getrusage(who, &e);
|
||||
auto tp1 = Clock::now();
|
||||
|
||||
std::cout << prefix;
|
||||
std::cout << "[" << std::this_thread::get_id() << "] ";
|
||||
std::cout << "time: ";
|
||||
std::cout << "real " << std::chrono::duration<double>(tp1 - tp0).count() << " ";
|
||||
std::cout << "user " << tvdiff(b.ru_utime, e.ru_utime) << " ";
|
||||
std::cout << "sys " << tvdiff(b.ru_stime, e.ru_stime);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
#endif
|
26
bench/graspels/decl.h
Normal file
26
bench/graspels/decl.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef ROSA_BENCH_GRASPELS_DECL_H
|
||||
#define ROSA_BENCH_GRASPELS_DECL_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution none(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution hwElsGen(tsp::Solution const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution hw_seq_v(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution hw_par_v(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution sk_nr_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_nr_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution sk_seq(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_firstlevel(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_staticpool(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_dynamicpool(tsp::Problem const&, RNG&, Arguments const&);
|
||||
tsp::Solution sk_par_thread(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const&, RNG&, Arguments const&);
|
||||
|
||||
#endif
|
220
bench/graspels/hw.cpp
Normal file
220
bench/graspels/hw.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
#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);
|
||||
}
|
188
bench/graspels/hwv.cpp
Normal file
188
bench/graspels/hwv.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "common.h"
|
||||
|
||||
auto hwElsGenV(tsp::Solution const& solution, RNG& rng) {
|
||||
return Descent{}(Move2Opt{}(solution, rng));
|
||||
}
|
||||
|
||||
auto hwElsInner(tsp::Solution const& solution, std::vector<RNG>& rngs, std::size_t id, std::size_t nCore) {
|
||||
std::size_t n = ELS_GEN;
|
||||
std::size_t maxThreads = nCore;
|
||||
|
||||
std::size_t const nThreads = std::min<std::size_t>(maxThreads, ELS_GEN);
|
||||
|
||||
std::vector<std::thread> threads{nThreads-1};
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto run = [&solution,&rngs](tsp::Solution& out, std::size_t id, std::size_t k) {
|
||||
tsp::Solution best{};
|
||||
|
||||
if(k)
|
||||
best = hwElsGenV(solution, rngs[id]);
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
tsp::Solution current = hwElsGenV(solution, rngs[id+i]);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<tsp::Solution> bests(nThreads);
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), id+start, step+offset};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[nThreads-1], id+start, step);
|
||||
|
||||
for(auto& thread: threads) thread.join();
|
||||
|
||||
tsp::Solution best;
|
||||
// best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = selectMin(std::move(best), std::move(bests[i]));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwEls(tsp::Solution const& solution, std::vector<RNG>& rngs, std::size_t id, 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, rngs, id, nCore);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto hwGraspGen(tsp::Problem const& problem, std::vector<RNG>& rngs, std::size_t id, std::size_t nCore = 1) {
|
||||
return hwEls(rgreedy()(problem, rngs[id]), rngs, id, nCore);
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
auto hwGraspEls(tsp::Problem const& problem, std::vector<RNG>& rngs) {
|
||||
tsp::Solution best;
|
||||
|
||||
auto graspIter = [&](tsp::Problem const& problem, tsp::Solution& s, std::size_t id) {
|
||||
tsp::Solution cur = hwGraspGen(problem, rngs, id);
|
||||
s = selectMin(std::move(s), std::move(cur));
|
||||
};
|
||||
|
||||
if(GRASP_N) {
|
||||
auto graspInit = [&](tsp::Problem const& problem, tsp::Solution& s) {
|
||||
s = hwGraspGen(problem, rngs, 0);
|
||||
};
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", graspInit, problem, best);
|
||||
#else
|
||||
graspInit(problem, best);
|
||||
#endif
|
||||
}
|
||||
|
||||
for(std::size_t i = 1; i < GRASP_N; ++i) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", graspIter, problem, best, i*ELS_GEN);
|
||||
#else
|
||||
graspIter(problem, best, i*ELS_GEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
auto hwGraspElsPar(tsp::Problem const& problem, std::vector<RNG>& rngs) {
|
||||
std::size_t const n = GRASP_N;
|
||||
std::size_t const maxThreads = K;
|
||||
|
||||
std::size_t const nThreads = std::min<std::size_t>(maxThreads, n);
|
||||
std::size_t const cores = maxThreads/nThreads;
|
||||
|
||||
std::vector<std::thread> threads(nThreads-1);
|
||||
std::size_t const step = n/nThreads;
|
||||
std::size_t const remainBase = n - step*nThreads;
|
||||
std::size_t remain = remainBase;
|
||||
|
||||
auto iter0 = [&problem,&rngs](tsp::Solution& best, std::size_t id, std::size_t cores) {
|
||||
best = hwGraspGen(problem, rngs, id, cores);
|
||||
};
|
||||
auto iter = [&problem,&rngs](tsp::Solution& best, std::size_t id, std::size_t cores) {
|
||||
tsp::Solution current = hwGraspGen(problem, rngs, id, cores);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
};
|
||||
|
||||
auto run = [&](tsp::Solution& out, std::size_t id, std::size_t k, std::size_t cores) {
|
||||
tsp::Solution best{};
|
||||
|
||||
if(k) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", iter0, best, id*ELS_GEN, cores);
|
||||
#else
|
||||
iter0(best, id*ELS_GEN, cores);
|
||||
#endif
|
||||
}
|
||||
|
||||
for(std::size_t i = 1; i < k; ++i) {
|
||||
#ifdef SUBTIME
|
||||
timeit(RUSAGE_THREAD, "[GRASP] ", iter, best, (id+i)*ELS_GEN, cores);
|
||||
#else
|
||||
iter(best, (id+1)*ELS_GEN, cores);
|
||||
#endif
|
||||
}
|
||||
|
||||
out = std::move(best);
|
||||
};
|
||||
|
||||
std::size_t start{};
|
||||
std::vector<tsp::Solution> bests(nThreads);
|
||||
|
||||
for(std::size_t i = 0; i < nThreads-1; ++i) {
|
||||
std::size_t offset = !!remain;
|
||||
remain -= offset;
|
||||
threads[i] = std::thread{run, std::ref(bests[i]), start, step+offset, cores};
|
||||
start += step+offset;
|
||||
}
|
||||
|
||||
run(bests[nThreads-1], start, step, cores);
|
||||
|
||||
for(std::thread& thread: threads) thread.join();
|
||||
|
||||
tsp::Solution best;
|
||||
if(nThreads) best = std::move(bests[0]);
|
||||
for(std::size_t i = 1; i < nThreads; ++i)
|
||||
best = selectMin(std::move(best), std::move(bests[i]));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
tsp::Solution hw_seq_v(tsp::Problem const& p, RNG& seeder, Arguments const&) {
|
||||
std::size_t n = GRASP_N * ELS_GEN;
|
||||
|
||||
std::vector<RNG> rngs;
|
||||
rngs.reserve(n);
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
rngs.emplace_back(seeder());
|
||||
|
||||
return hwGraspEls(p, rngs);
|
||||
}
|
||||
|
||||
tsp::Solution hw_par_v(tsp::Problem const& p, RNG& seeder, Arguments const&) {
|
||||
std::size_t n = GRASP_N * ELS_GEN;
|
||||
|
||||
std::vector<RNG> rngs;
|
||||
rngs.reserve(n);
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
rngs.emplace_back(seeder());
|
||||
|
||||
return hwGraspElsPar<NTHREADS>(p, rngs);
|
||||
}
|
49
bench/graspels/main.cpp
Normal file
49
bench/graspels/main.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <getopt.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "common.h"
|
||||
#include "decl.h"
|
||||
|
||||
Arguments cli(int argc, char **argv) {
|
||||
int option_index, option;
|
||||
struct option long_options[] = {
|
||||
{"seed", required_argument, 0, 's' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
Arguments args;
|
||||
args.seed = SEED;
|
||||
|
||||
optind = 0;
|
||||
while((option = getopt_long(argc, argv,
|
||||
"" "" "" "s:",
|
||||
long_options, &option_index)) != -1) {
|
||||
switch(option) {
|
||||
case 's': {
|
||||
std::istringstream iss{optarg};
|
||||
iss >> args.seed;
|
||||
} break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
Arguments args = cli(argc, argv);
|
||||
|
||||
tsp::Tsp tspData{DATA_FILE};
|
||||
tsp::Problem problem{tspData.points()};
|
||||
RNG rng{args.seed};
|
||||
|
||||
std::printf("conf: f: %s, data: %s, grasp: %s, outer: %s, inner: %s, threads: %s, seed: %zu\n",
|
||||
STR(FUNC), STR(DATA_FILE), STR(GRASP_N), STR(ELS_ITER_MAX), STR(ELS_GEN), STR(NTHREADS), args.seed);
|
||||
|
||||
tsp::Solution s;
|
||||
auto task = [&]{ s = FUNC(problem, rng, args); };
|
||||
|
||||
timeit(RUSAGE_SELF, "", task);
|
||||
|
||||
std::cout << "result: " << s.value() << std::endl;
|
||||
}
|
18
bench/graspels/none.cpp
Normal file
18
bench/graspels/none.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution none(tsp::Problem const&, RNG&, Arguments const&) {
|
||||
std::cout << 1+R"(
|
||||
Options:
|
||||
- DATA_FILE
|
||||
- GRASP_N
|
||||
- ELS_ITER_MAX
|
||||
- ELS_GEN
|
||||
- FUNC (mandatory)
|
||||
|
||||
Example:
|
||||
- g++ -Wall -Wextra -O2 -Isrc -Iinc -pthread src/tsp/*.cpp -DFUNC=sk_par2 -DNTHREADS=4 bench/graspels/*.cpp
|
||||
)";
|
||||
|
||||
return {};
|
||||
}
|
||||
|
37
bench/graspels/nrsk.cpp
Normal file
37
bench/graspels/nrsk.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "bad_graspels.h"
|
||||
#include "common.h"
|
||||
|
||||
using NRELS = rosa::SkelNREls<
|
||||
tsp::Solution, RNG,
|
||||
Descent,
|
||||
Move2Opt, Descent, FN(selectMin)
|
||||
>;
|
||||
|
||||
using NRGRASPxELS = rosa::SkelNRGrasp<
|
||||
tsp::Problem, tsp::Solution, RNG,
|
||||
RGreedy<tsp::Solution>, NRELS,
|
||||
FN(selectMin)
|
||||
>;
|
||||
|
||||
tsp::Solution sk_nr_seq(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::Sequential, NRGRASPxELS>();
|
||||
graspEls.executor.repeatability.disabled();
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p, rng);
|
||||
}
|
||||
|
||||
tsp::Solution sk_nr_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::FirstLevelNoOpti, NRGRASPxELS>();
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.executor.repeatability.disabled();
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p, rng);
|
||||
}
|
74
bench/graspels/sk.cpp
Normal file
74
bench/graspels/sk.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include "common.h"
|
||||
|
||||
using ELS = rosa::SkelEls<
|
||||
tsp::Solution,
|
||||
Descent,
|
||||
Move2Opt, Descent, FN(selectMin)
|
||||
>;
|
||||
|
||||
using GRASPxELS = rosa::SkelGrasp<
|
||||
tsp::Problem, tsp::Solution,
|
||||
RGreedy<tsp::Solution>, ELS,
|
||||
FN(selectMin)
|
||||
>;
|
||||
|
||||
tsp::Solution sk_seq(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::Sequential, GRASPxELS>();
|
||||
graspEls.executor.repeatability.upTo(4);
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = 1;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_firstlevel(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::FirstLevelEqui, GRASPxELS>();
|
||||
graspEls.executor.repeatability.upTo(4);
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_staticpool(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::StaticPool, GRASPxELS>();
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_dynamicpool(tsp::Problem const& p, RNG&, Arguments const& args) {
|
||||
auto graspEls = alsk::implement<alsk::exec::DynamicPool, GRASPxELS>();
|
||||
graspEls.state.context.seed = args.seed;
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
||||
|
||||
tsp::Solution sk_par_thread(tsp::Problem const& p, RNG&, Arguments const&) {
|
||||
auto graspEls = alsk::implement<alsk::exec::StaticThread, GRASPxELS>();
|
||||
graspEls.executor.cores = NTHREADS;
|
||||
graspEls.skeleton.task.task<0>() = rgreedy();
|
||||
graspEls.skeleton.task.task<1>().task<1>().n = ELS_ITER_MAX;
|
||||
graspEls.skeleton.task.task<1>().task<1>().task.n = ELS_GEN;
|
||||
graspEls.skeleton.n = GRASP_N;
|
||||
|
||||
return graspEls(p);
|
||||
}
|
111
bench/graspels/tbb.cpp
Normal file
111
bench/graspels/tbb.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
#ifdef WITH_TBB
|
||||
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
#include <tbb/flow_graph.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "decl.h"
|
||||
|
||||
/* *** */
|
||||
/* TBB */
|
||||
|
||||
auto tbbElsInner(tsp::Solution const& solution, RNG& rng, std::size_t nCore) {
|
||||
tsp::Solution best;
|
||||
std::vector<tsp::Solution> solutions(ELS_GEN);
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(ELS_GEN);
|
||||
for(std::size_t i = 0; i < ELS_GEN; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
using ElsGenP = std::tuple<tsp::Solution const*, RNG*, tsp::Solution*>;
|
||||
using ElsGenR = std::tuple<tsp::Solution, tsp::Solution*>;
|
||||
|
||||
tbb::flow::graph g;
|
||||
tbb::flow::function_node<ElsGenP, ElsGenR> fElsGen(g, nCore,
|
||||
[](ElsGenP t) { return std::make_tuple(hwElsGen(*std::get<0>(t), *std::get<1>(t)), std::get<2>(t)); }
|
||||
);
|
||||
tbb::flow::function_node<ElsGenR, bool> fSelectMin(g, nCore,
|
||||
[](ElsGenR t) { *std::get<1>(t) = (selectMin(std::get<0>(t), *std::get<1>(t))); return true; }
|
||||
);
|
||||
|
||||
tbb::flow::make_edge(fElsGen, fSelectMin);
|
||||
|
||||
if(ELS_GEN)
|
||||
solutions[0] = hwElsGen(solution, rngs[0]);
|
||||
for(std::size_t i = 1; i < ELS_GEN; ++i)
|
||||
fElsGen.try_put(std::make_tuple(&solution, &rngs[i], &solutions[i]));
|
||||
|
||||
g.wait_for_all();
|
||||
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
return best;
|
||||
}
|
||||
|
||||
auto tbbEls(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 = tbbElsInner(best, rng, nCore);
|
||||
best = selectMin(std::move(best), std::move(current));
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
auto tbbGraspGen(tsp::Problem const& problem, RNG& rng, std::size_t nCore) {
|
||||
return tbbEls(rgreedy()(problem, rng), rng, nCore);
|
||||
}
|
||||
|
||||
template<std::size_t K>
|
||||
tsp::Solution tbbGraspElsPar(tsp::Problem const& problem, RNG& rng) {
|
||||
tsp::Solution best;
|
||||
std::vector<tsp::Solution> solutions(GRASP_N);
|
||||
|
||||
tbb::task_scheduler_init init(K);
|
||||
|
||||
/* repeatability at loop level */
|
||||
std::vector<RNG> rngs(GRASP_N);
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
rngs[i].seed(rng());
|
||||
/* ***** */
|
||||
|
||||
using GraspGenP = std::tuple<tsp::Problem const*, RNG*, unsigned long, tsp::Solution*>;
|
||||
using GraspGenR = std::tuple<tsp::Solution, tsp::Solution*>;
|
||||
|
||||
tbb::flow::graph g;
|
||||
tbb::flow::function_node<GraspGenP, GraspGenR> fGraspGen(g, K,
|
||||
[](GraspGenP t) { return std::make_tuple(tbbGraspGen(*std::get<0>(t), *std::get<1>(t), std::get<2>(t)), std::get<3>(t)); }
|
||||
);
|
||||
tbb::flow::function_node<GraspGenR, bool> fSelectMin(g, K,
|
||||
[](GraspGenR t) { *std::get<1>(t) = (selectMin(std::get<0>(t), *std::get<1>(t))); return true; }
|
||||
);
|
||||
|
||||
tbb::flow::make_edge(fGraspGen, fSelectMin);
|
||||
|
||||
for(std::size_t i = 0; i < GRASP_N; ++i)
|
||||
fGraspGen.try_put(std::make_tuple(&problem, &rngs[i], K, &solutions[i]));
|
||||
|
||||
g.wait_for_all();
|
||||
|
||||
/* Selection */
|
||||
best = *std::min_element(std::begin(solutions), std::end(solutions));
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const& p, RNG& rng, Arguments const&) {
|
||||
return tbbGraspElsPar<NTHREADS>(p, rng);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "common.h"
|
||||
|
||||
tsp::Solution tbb_par(tsp::Problem const&, RNG&, Arguments const&) {
|
||||
std::clog << "must compile with -ltbb -DWITH_TBB to enable TBB\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user