From a0002af636b4e10dc296d5145db54e34111ac093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Pascoal?= Date: Sun, 26 Jun 2022 23:57:45 +0100 Subject: [PATCH] Add logs to implemented algorithms --- src/algorithms/ant_colony.cpp | 7 ++++++- src/algorithms/ant_colony.hpp | 2 +- src/algorithms/greedy.cpp | 5 ++++- src/algorithms/greedy.hpp | 2 +- src/algorithms/simulated_annealing.cpp | 12 +++++++++--- src/algorithms/simulated_annealing.hpp | 2 +- src/algorithms/tabu_search.cpp | 20 ++++++++++++++------ src/algorithms/tabu_search.hpp | 4 ++-- src/analysis/metaheuristics.cpp | 12 ++++++++++-- src/cvrp/stage_2.cpp | 26 +++++++++++++------------- src/cvrp/stage_2.hpp | 2 +- src/main.cpp | 2 +- 12 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/algorithms/ant_colony.cpp b/src/algorithms/ant_colony.cpp index 70552f6..908a95f 100644 --- a/src/algorithms/ant_colony.cpp +++ b/src/algorithms/ant_colony.cpp @@ -13,7 +13,7 @@ using namespace std; static random_device rd; static mt19937 rng(rd()); -CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig config) { +CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig config, bool printLogs) { CvrpSolution bestSolution = { {}, numeric_limits::max() }; const vector& deliveries = instance.getDeliveries(); @@ -149,6 +149,8 @@ CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig if (solution.length < bestSolution.length) { bestSolution = solution; + if (printLogs) cout << "New best solution: " + << bestSolution.length / 1000.0 << endl; } if (config.eliteAnts == 0) { @@ -183,5 +185,8 @@ CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig } } + if (printLogs) cout << "Final solution has length " << bestSolution.length / 1000.0 << ", uses " + << bestSolution.routes.size() << " vehicles." << endl; + return bestSolution; } diff --git a/src/algorithms/ant_colony.hpp b/src/algorithms/ant_colony.hpp index b71d93f..9fa5b2d 100644 --- a/src/algorithms/ant_colony.hpp +++ b/src/algorithms/ant_colony.hpp @@ -12,6 +12,6 @@ struct AntColonyConfig { bool useSwapHeuristic = true; }; -CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig config); +CvrpSolution antColonyOptimization(const CvrpInstance& instance, AntColonyConfig config, bool printLogs = false); #endif // ANT_COLONY_H diff --git a/src/algorithms/greedy.cpp b/src/algorithms/greedy.cpp index 9b9ca7a..0111e9b 100644 --- a/src/algorithms/greedy.cpp +++ b/src/algorithms/greedy.cpp @@ -5,7 +5,7 @@ using namespace std; -CvrpSolution greedyAlgorithm(const CvrpInstance& instance) { +CvrpSolution greedyAlgorithm(const CvrpInstance& instance, bool printLogs) { double capacity = instance.getVehicleCapacity(); const vector& deliveries = instance.getDeliveries(); const vector>& dm = instance.getDistanceMatrix(); @@ -46,5 +46,8 @@ CvrpSolution greedyAlgorithm(const CvrpInstance& instance) { currentRoute.push_back(0); routes.push_back(currentRoute); + if (printLogs) cout << "Final solution has length " << length / 1000.0 << ", uses " + << routes.size() << " vehicles." << endl; + return { routes, length }; } diff --git a/src/algorithms/greedy.hpp b/src/algorithms/greedy.hpp index 461e47c..959c994 100644 --- a/src/algorithms/greedy.hpp +++ b/src/algorithms/greedy.hpp @@ -4,6 +4,6 @@ #include "../cvrp/cvrp.hpp" -CvrpSolution greedyAlgorithm(const CvrpInstance& instance); +CvrpSolution greedyAlgorithm(const CvrpInstance& instance, bool printLogs = false); #endif diff --git a/src/algorithms/simulated_annealing.cpp b/src/algorithms/simulated_annealing.cpp index 2ed4379..07e6c2b 100644 --- a/src/algorithms/simulated_annealing.cpp +++ b/src/algorithms/simulated_annealing.cpp @@ -119,7 +119,7 @@ vector randomValidNeighbor(const CvrpInstance& instance, const vector& return neighbor; } -vector simulatedAnnealingAlgorithm(const CvrpInstance& instance, const SimulatedAnnealingConfig& config) { +vector simulatedAnnealingAlgorithm(const CvrpInstance& instance, const SimulatedAnnealingConfig& config, bool printLogs) { srand(time(NULL)); uniform_real_distribution dist; const vector>& distanceMatrix = instance.getDistanceMatrix(); @@ -130,6 +130,8 @@ vector simulatedAnnealingAlgorithm(const CvrpInstance& instance, const Simu vector bestSolution = currentSolution; double bestLength = currentLength; + if (printLogs) cout << "Initial solution: " << currentLength / 1000.0 << endl; + double temperature = bestLength; double temperatureDecrease = pow(MIN_TEMPERATURE / temperature, 1.0 / (config.numIters - 1.0)); @@ -140,6 +142,7 @@ vector simulatedAnnealingAlgorithm(const CvrpInstance& instance, const Simu if (newLength < bestLength) { bestSolution = newSolution; bestLength = newLength; + if (printLogs) cout << "New best solution: " << bestLength / 1000.0 << endl; } double delta = newLength - currentLength; @@ -155,10 +158,10 @@ vector simulatedAnnealingAlgorithm(const CvrpInstance& instance, const Simu return bestSolution; } -CvrpSolution simulatedAnnealing(const CvrpInstance& instance, SimulatedAnnealingConfig config) { +CvrpSolution simulatedAnnealing(const CvrpInstance& instance, SimulatedAnnealingConfig config, bool printLogs) { srand(time(nullptr)); - vector solution = simulatedAnnealingAlgorithm(instance, config); + vector solution = simulatedAnnealingAlgorithm(instance, config, printLogs); // Normalize solution const vector>& distanceMatrix = instance.getDistanceMatrix(); @@ -178,5 +181,8 @@ CvrpSolution simulatedAnnealing(const CvrpInstance& instance, SimulatedAnnealing currentRoute.push_back(0); if (currentRoute.size() > 2) routes.push_back(currentRoute); + if (printLogs) cout << "Final solution has length " << length / 1000.0 << ", uses " + << routes.size() << " vehicles." << endl; + return { routes, length }; } diff --git a/src/algorithms/simulated_annealing.hpp b/src/algorithms/simulated_annealing.hpp index 392c89e..6a86d5e 100644 --- a/src/algorithms/simulated_annealing.hpp +++ b/src/algorithms/simulated_annealing.hpp @@ -15,6 +15,6 @@ struct SimulatedAnnealingConfig { size_t numIters = 10'000'000; }; -CvrpSolution simulatedAnnealing(const CvrpInstance& instance, SimulatedAnnealingConfig config); +CvrpSolution simulatedAnnealing(const CvrpInstance& instance, SimulatedAnnealingConfig config, bool printLogs = false); #endif // SIMULATED_ANNEALING_H diff --git a/src/algorithms/tabu_search.cpp b/src/algorithms/tabu_search.cpp index 3c3d14b..b3f2a04 100644 --- a/src/algorithms/tabu_search.cpp +++ b/src/algorithms/tabu_search.cpp @@ -120,7 +120,7 @@ class ClarkeWrightRoute { u32 ClarkeWrightRoute::nextId = 0; -CvrpSolution clarkeWrightSavings(const CvrpInstance& instance) { +CvrpSolution clarkeWrightSavings(const CvrpInstance& instance, bool printLogs) { const vector>& distanceMatrix = instance.getDistanceMatrix(); list routes; @@ -200,6 +200,9 @@ CvrpSolution clarkeWrightSavings(const CvrpInstance& instance) { length += route.getLength(); } + if (printLogs) cout << "Clarke-Wright Savings solution has length " + << length / 1000.0 << ", uses " << convertedRoutes.size() << " vehicles" << endl; + return { convertedRoutes, length }; } @@ -325,10 +328,10 @@ static mt19937 rng(rd()); static const u32 MIN_PENALTY = 1, MAX_PENALTY = 6400, INITIAL_PENALTY = 100, PENALTY_UPDATE_ITERS = 10; -CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIterations, double beta) { +CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIterations, double beta, bool printLogs) { typedef function TabuSearchHeuristic; - CvrpSolution initialSolution = clarkeWrightSavings(instance); + CvrpSolution initialSolution = clarkeWrightSavings(instance, printLogs); const vector>& distanceMatrix = instance.getDistanceMatrix(); auto isShort = [&beta, &instance, &initialSolution](const Edge& edge) { @@ -345,8 +348,6 @@ CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIteratio } currentSolution = bestSolution; - cout << "Clarke-Wright initial solution has length " << bestSolution.length / 1000 << "km" << endl; - uniform_int_distribution tenureDistribution(5, 10); unordered_map tabuList; u32 penalty = INITIAL_PENALTY, valid = 0; @@ -366,7 +367,7 @@ CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIteratio for (size_t idxB = 1; idxB < tsrB.route.size() - 1; ++idxB) { if (isShort({tsrA.route[idxA], tsrB.route[idxB]})) { auto applyHeuristic = [&instance, &tabuList, &penalty, &iterationBest, &removedEdges, - &bestSolution, ¤tSolution, &movesEvaluated, ra, rb, idxA, idxB] + &bestSolution, ¤tSolution, &movesEvaluated, printLogs, ra, rb, idxA, idxB] (const TabuSearchHeuristic& heuristic) { TabuSearchSolution newSolution = currentSolution; TabuSearchEdge edge = {idxA, idxB, newSolution.routes[ra], newSolution.routes[rb]}; @@ -386,6 +387,7 @@ CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIteratio if (newSolution.length < bestSolution.length && newSolution.isValid(instance)) { bestSolution = newSolution; + if (printLogs) cout << "New best solution: " << bestSolution.length / 1000.0 << endl; } if (!tabu) { @@ -410,6 +412,9 @@ CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIteratio } } + if (printLogs) cout << "ITERATION " << iter << ": Evaluated " << movesEvaluated + << " moves." << endl; + if (iterationBest->isValid(instance)) ++valid; for (auto& route : iterationBest->routes) { @@ -446,5 +451,8 @@ CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIteratio } } + if (printLogs) cout << "Final solution has length " << bestSolution.length / 1000.0 << ", uses " + << bestSolution.routes.size() << " vehicles." << endl; + return bestSolution.toStandardForm(); } diff --git a/src/algorithms/tabu_search.hpp b/src/algorithms/tabu_search.hpp index 517646e..caf0c32 100644 --- a/src/algorithms/tabu_search.hpp +++ b/src/algorithms/tabu_search.hpp @@ -4,8 +4,8 @@ #include "../cvrp/cvrp.hpp" -CvrpSolution clarkeWrightSavings(const CvrpInstance& instance); +CvrpSolution clarkeWrightSavings(const CvrpInstance& instance, bool printLogs = false); -CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIterations = 1000, double beta = 1.5); +CvrpSolution granularTabuSearch(const CvrpInstance& instance, size_t maxIterations = 1000, double beta = 1.5, bool printLogs = false); #endif // TABU_SEARCH_H \ No newline at end of file diff --git a/src/analysis/metaheuristics.cpp b/src/analysis/metaheuristics.cpp index 627eda8..b24ad7d 100644 --- a/src/analysis/metaheuristics.cpp +++ b/src/analysis/metaheuristics.cpp @@ -51,6 +51,14 @@ void printResults(ofstream& ofs, const string& name, const CvrpInstance& instanc << averageCargo << ")" << endl; } +CvrpSolution greedyAlgorithmDefault(const CvrpInstance& instance) { + return greedyAlgorithm(instance); +} + +CvrpSolution clarkeWrightSavingsDefault(const CvrpInstance& instance) { + return clarkeWrightSavings(instance); +} + CvrpSolution simulatedAnnealingDefault(const CvrpInstance& instance) { SimulatedAnnealingConfig config; return simulatedAnnealing(instance, config); @@ -80,8 +88,8 @@ void metaheuristicComparison() { static const array iterations = {1, 1, 5, 1, 1}; static array, NUM_METAHEURISTICS> functions = { - greedyAlgorithm, - clarkeWrightSavings, + greedyAlgorithmDefault, + clarkeWrightSavingsDefault, simulatedAnnealingDefault, granularTabuSearchDefault, antColonyOptimizationDefault, diff --git a/src/cvrp/stage_2.cpp b/src/cvrp/stage_2.cpp index 1ad12aa..54402ea 100644 --- a/src/cvrp/stage_2.cpp +++ b/src/cvrp/stage_2.cpp @@ -34,7 +34,7 @@ bool convertBool(const string& str) { return lower == "yes"; } -CvrpSolution applyAntColonyOptimization(const CvrpInstance& instance, bool config) { +CvrpSolution applyAntColonyOptimization(const CvrpInstance& instance, bool config, bool printLogs) { AntColonyConfig acoConfig; if (config) { @@ -46,14 +46,14 @@ CvrpSolution applyAntColonyOptimization(const CvrpInstance& instance, bool confi readOption(acoConfig.useSwapHeuristic, "Use swap heuristic (yes / no): ", convertBool); } - return antColonyOptimization(instance, acoConfig); + return antColonyOptimization(instance, acoConfig, printLogs); } -CvrpSolution applyClarkeWrightSavings(const CvrpInstance& instance, bool config) { - return clarkeWrightSavings(instance); +CvrpSolution applyClarkeWrightSavings(const CvrpInstance& instance, bool config, bool printLogs) { + return clarkeWrightSavings(instance, printLogs); } -CvrpSolution applyGranularTabuSearch(const CvrpInstance& instance, bool config) { +CvrpSolution applyGranularTabuSearch(const CvrpInstance& instance, bool config, bool printLogs) { size_t maxIterations = 1000; double beta = 1.5; @@ -62,14 +62,14 @@ CvrpSolution applyGranularTabuSearch(const CvrpInstance& instance, bool config) readOption(beta, "Beta: ", convertDouble); } - return granularTabuSearch(instance, maxIterations, beta); + return granularTabuSearch(instance, maxIterations, beta, printLogs); } -CvrpSolution applyGreedyAlgorithm(const CvrpInstance& instance, bool config) { - return greedyAlgorithm(instance); +CvrpSolution applyGreedyAlgorithm(const CvrpInstance& instance, bool config, bool printLogs) { + return greedyAlgorithm(instance, printLogs); } -CvrpSolution applySimulatedAnnealing(const CvrpInstance& instance, bool config) { +CvrpSolution applySimulatedAnnealing(const CvrpInstance& instance, bool config, bool printLogs) { SimulatedAnnealingConfig saConfig; if (config) { @@ -82,11 +82,11 @@ CvrpSolution applySimulatedAnnealing(const CvrpInstance& instance, bool config) readOption(saConfig.numIters, "Num. iterations: ", convertUnsignedInt); } - return simulatedAnnealing(instance, saConfig); + return simulatedAnnealing(instance, saConfig, printLogs); } -CvrpSolution applyCvrpAlgorithm(string algorithm, const CvrpInstance& instance, bool config) { - static const unordered_map> algorithms = { +CvrpSolution applyCvrpAlgorithm(string algorithm, const CvrpInstance& instance, bool config, bool printLogs) { + static const unordered_map> algorithms = { {"aco", applyAntColonyOptimization}, {"cws", applyClarkeWrightSavings}, {"gts", applyGranularTabuSearch}, @@ -95,7 +95,7 @@ CvrpSolution applyCvrpAlgorithm(string algorithm, const CvrpInstance& instance, }; if (algorithms.count(algorithm.c_str())) { - return algorithms.at(algorithm.c_str())(instance, config); + return algorithms.at(algorithm.c_str())(instance, config, printLogs); } return { {} , 0 }; diff --git a/src/cvrp/stage_2.hpp b/src/cvrp/stage_2.hpp index 55905af..e6e1923 100644 --- a/src/cvrp/stage_2.hpp +++ b/src/cvrp/stage_2.hpp @@ -5,6 +5,6 @@ #include #include "cvrp.hpp" -CvrpSolution applyCvrpAlgorithm(std::string algorithm, const CvrpInstance& instance, bool config); +CvrpSolution applyCvrpAlgorithm(std::string algorithm, const CvrpInstance& instance, bool config, bool printLogs); #endif // CVRP_STAGE_2_H diff --git a/src/main.cpp b/src/main.cpp index 7a3f7d5..f4f7745 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -148,7 +148,7 @@ int main(int argc, char** argv) { } } - CvrpSolution solution = applyCvrpAlgorithm(cvrpAlgorithm, instance, config); + CvrpSolution solution = applyCvrpAlgorithm(cvrpAlgorithm, instance, config, logs); cout << "Final solution has length " << solution.length / 1000.0 << " and uses " << solution.routes.size() << " vehicles." << endl;