Skip to content

Commit

Permalink
Add logs to implemented algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
GoncaloPascoal committed Jun 26, 2022
1 parent c59f9bc commit a0002af
Showing 12 changed files with 63 additions and 33 deletions.
7 changes: 6 additions & 1 deletion src/algorithms/ant_colony.cpp
Original file line number Diff line number Diff line change
@@ -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<double>::max() };

const vector<CvrpDelivery>& 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;
}
2 changes: 1 addition & 1 deletion src/algorithms/ant_colony.hpp
Original file line number Diff line number Diff line change
@@ -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
5 changes: 4 additions & 1 deletion src/algorithms/greedy.cpp
Original file line number Diff line number Diff line change
@@ -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<CvrpDelivery>& deliveries = instance.getDeliveries();
const vector<vector<double>>& 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 };
}
2 changes: 1 addition & 1 deletion src/algorithms/greedy.hpp
Original file line number Diff line number Diff line change
@@ -4,6 +4,6 @@

#include "../cvrp/cvrp.hpp"

CvrpSolution greedyAlgorithm(const CvrpInstance& instance);
CvrpSolution greedyAlgorithm(const CvrpInstance& instance, bool printLogs = false);

#endif
12 changes: 9 additions & 3 deletions src/algorithms/simulated_annealing.cpp
Original file line number Diff line number Diff line change
@@ -119,7 +119,7 @@ vector<u64> randomValidNeighbor(const CvrpInstance& instance, const vector<u64>&
return neighbor;
}

vector<u64> simulatedAnnealingAlgorithm(const CvrpInstance& instance, const SimulatedAnnealingConfig& config) {
vector<u64> simulatedAnnealingAlgorithm(const CvrpInstance& instance, const SimulatedAnnealingConfig& config, bool printLogs) {
srand(time(NULL));
uniform_real_distribution dist;
const vector<vector<double>>& distanceMatrix = instance.getDistanceMatrix();
@@ -130,6 +130,8 @@ vector<u64> simulatedAnnealingAlgorithm(const CvrpInstance& instance, const Simu
vector<u64> 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<u64> 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<u64> 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<u64> solution = simulatedAnnealingAlgorithm(instance, config);
vector<u64> solution = simulatedAnnealingAlgorithm(instance, config, printLogs);

// Normalize solution
const vector<vector<double>>& 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 };
}
2 changes: 1 addition & 1 deletion src/algorithms/simulated_annealing.hpp
Original file line number Diff line number Diff line change
@@ -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
20 changes: 14 additions & 6 deletions src/algorithms/tabu_search.cpp
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ class ClarkeWrightRoute {

u32 ClarkeWrightRoute::nextId = 0;

CvrpSolution clarkeWrightSavings(const CvrpInstance& instance) {
CvrpSolution clarkeWrightSavings(const CvrpInstance& instance, bool printLogs) {
const vector<vector<double>>& distanceMatrix = instance.getDistanceMatrix();

list<ClarkeWrightRoute> 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<void(const CvrpInstance&, TabuSearchSolution&, TabuSearchEdge&)> TabuSearchHeuristic;

CvrpSolution initialSolution = clarkeWrightSavings(instance);
CvrpSolution initialSolution = clarkeWrightSavings(instance, printLogs);
const vector<vector<double>>& 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<int> tenureDistribution(5, 10);
unordered_map<Edge, u8, PairHash> 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, &currentSolution, &movesEvaluated, ra, rb, idxA, idxB]
&bestSolution, &currentSolution, &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();
}
4 changes: 2 additions & 2 deletions src/algorithms/tabu_search.hpp
Original file line number Diff line number Diff line change
@@ -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
12 changes: 10 additions & 2 deletions src/analysis/metaheuristics.cpp
Original file line number Diff line number Diff line change
@@ -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<u32, NUM_METAHEURISTICS> iterations = {1, 1, 5, 1, 1};
static array<function<CvrpSolution(const CvrpInstance&)>, NUM_METAHEURISTICS> functions = {
greedyAlgorithm,
clarkeWrightSavings,
greedyAlgorithmDefault,
clarkeWrightSavingsDefault,
simulatedAnnealingDefault,
granularTabuSearchDefault,
antColonyOptimizationDefault,
26 changes: 13 additions & 13 deletions src/cvrp/stage_2.cpp
Original file line number Diff line number Diff line change
@@ -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<bool>(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<double>(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<u64>(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<string, function<CvrpSolution(const CvrpInstance&, bool)>> algorithms = {
CvrpSolution applyCvrpAlgorithm(string algorithm, const CvrpInstance& instance, bool config, bool printLogs) {
static const unordered_map<string, function<CvrpSolution(const CvrpInstance&, bool, bool)>> 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 };
2 changes: 1 addition & 1 deletion src/cvrp/stage_2.hpp
Original file line number Diff line number Diff line change
@@ -5,6 +5,6 @@
#include <string>
#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
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit a0002af

Please sign in to comment.