Skip to content

Commit

Permalink
cleaning
Browse files Browse the repository at this point in the history
  • Loading branch information
lseman committed Sep 28, 2024
1 parent ba0fec5 commit a0c30d1
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<img src="docs/logo.png" alt="BALDES" width="300"/>
</td>
<td>
BALDES (pronounced /'baw-dɨs/) is a C++ implementation of a Bucket Graph-based labeling algorithm designed to solve the Resource-Constrained Shortest Path Problem (RSCPP), commonly used as a subproblem in state-of-the-art Branch-Cut-and-Price algorithms for various Vehicle Routing Problems (VRPs).
BALDES (pronounced /'baw-dɨs/) is a C++ implementation of a Bucket Graph-based labeling algorithm designed to solve the Resource-Constrained Shortest Path Problem (RCSPP), commonly used as a subproblem in state-of-the-art Branch-Cut-and-Price algorithms for various Vehicle Routing Problems (VRPs).
</td>
</tr>
</table>
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion examples/pstep.py → examples/python/pstep.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import sys

# Add the build directory to the Python path
sys.path.append(os.path.abspath("../build"))
sys.path.append(os.path.abspath("../../build"))

# %%

Expand Down
2 changes: 1 addition & 1 deletion python/runner.py → examples/python/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys

# Add the build directory to the Python path
sys.path.append(os.path.abspath('../build'))
sys.path.append(os.path.abspath('../../build'))

# Now you can import the BALDES module
import baldes
Expand Down
109 changes: 54 additions & 55 deletions third_party/hgs_vrptw/Genetic.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <algorithm>
#include <bitset>
#include <iterator>
#include <time.h>
#include <unordered_set>
Expand Down Expand Up @@ -120,33 +121,31 @@ Individual *Genetic::crossoverOX(std::pair<const Individual *, const Individual

void Genetic::doOXcrossover(Individual *result, std::pair<const Individual *, const Individual *> parents, int start,
int end) {
// Frequency vector to track the clients which have been inserted already
std::vector<bool> freqClient(params->nbClients + 1, false);
std::bitset<N_SIZE> freqClient; // Use bitset for better performance if MAX_NB_CLIENTS is known at compile-time
freqClient.reset(); // Clear the bitset

// Copy in place the elements from start to end
int j = start;
int nbClients = params->nbClients;
int idxEnd = (end + 1 == nbClients) ? 0 : end + 1; // Pre-compute the modulo result once
// Pre-compute the constants
const int nbClients = params->nbClients;
const int idxEnd = (end + 1 == nbClients) ? 0 : end + 1;

// First loop: directly copy the segment from parent A
int j = start;
while (j != idxEnd) {
result->chromT[j] = parents.first->chromT[j];
freqClient[result->chromT[j]] = true;
j++;
if (j == nbClients) j = 0; // Avoid modulo, just reset to 0 when reaching the end
int elem = parents.first->chromT[j];
result->chromT[j] = elem;
freqClient.set(elem);
if (++j == nbClients) j = 0;
}

// Fill the remaining elements from parent B, skipping already copied ones
int i = idxEnd; // Start right after the end
int i = idxEnd;
while (j != start) {
int temp = parents.second->chromT[i];
if (!freqClient[temp]) {
if (!freqClient.test(temp)) {
result->chromT[j] = temp;
j++;
if (j == nbClients) j = 0; // Avoid modulo
if (++j == nbClients) j = 0;
}
i++;
if (i == nbClients) i = 0; // Avoid modulo
if (++i == nbClients) i = 0;
}

// Completing the individual with the Split algorithm
Expand Down Expand Up @@ -183,71 +182,71 @@ Individual *Genetic::crossoverSREX(std::pair<const Individual *, const Individua

bool improved = true;
while (improved) {
const int idxALeft = (startA - 1 + nOfRoutesA) % nOfRoutesA;
const int idxARight = (startA + nOfMovedRoutes) % nOfRoutesA;
const int idxALastMoved = (startA + nOfMovedRoutes - 1) % nOfRoutesA;
const int idxBLeft = (startB - 1 + nOfRoutesB) % nOfRoutesB;
const int idxBRight = (startB + nOfMovedRoutes) % nOfRoutesB;
const int idxBLastMoved = (startB - 1 + nOfMovedRoutes) % nOfRoutesB;

// Cache counts for A and B
const auto countClientsOut = [](const std::vector<int> &route, const std::unordered_set<int> &clientsSet) {
return std::count_if(route.begin(), route.end(),
[&clientsSet](int c) { return clientsSet.find(c) == clientsSet.end(); });
};

const auto countClientsIn = [](const std::vector<int> &route, const std::unordered_set<int> &clientsSet) {
return std::count_if(route.begin(), route.end(),
[&clientsSet](int c) { return clientsSet.find(c) != clientsSet.end(); });
};

// Difference for moving 'left' in parent A
const int differenceALeft =
static_cast<int>(std::count_if(
parents.first->chromR[(startA - 1 + nOfRoutesA) % nOfRoutesA].begin(),
parents.first->chromR[(startA - 1 + nOfRoutesA) % nOfRoutesA].end(),
[&clientsInSelectedB](int c) { return clientsInSelectedB.find(c) == clientsInSelectedB.end(); })) -
static_cast<int>(std::count_if(
parents.first->chromR[(startA + nOfMovedRoutes - 1) % nOfRoutesA].begin(),
parents.first->chromR[(startA + nOfMovedRoutes - 1) % nOfRoutesA].end(),
[&clientsInSelectedB](int c) { return clientsInSelectedB.find(c) == clientsInSelectedB.end(); }));
const int differenceALeft = countClientsOut(parents.first->chromR[idxALeft], clientsInSelectedB) -
countClientsOut(parents.first->chromR[idxALastMoved], clientsInSelectedB);

// Difference for moving 'right' in parent A
const int differenceARight =
static_cast<int>(std::count_if(
parents.first->chromR[(startA + nOfMovedRoutes) % nOfRoutesA].begin(),
parents.first->chromR[(startA + nOfMovedRoutes) % nOfRoutesA].end(),
[&clientsInSelectedB](int c) { return clientsInSelectedB.find(c) == clientsInSelectedB.end(); })) -
static_cast<int>(std::count_if(
parents.first->chromR[startA].begin(), parents.first->chromR[startA].end(),
[&clientsInSelectedB](int c) { return clientsInSelectedB.find(c) == clientsInSelectedB.end(); }));
const int differenceARight = countClientsOut(parents.first->chromR[idxARight], clientsInSelectedB) -
countClientsOut(parents.first->chromR[startA], clientsInSelectedB);

// Difference for moving 'left' in parent B
const int differenceBLeft =
static_cast<int>(std::count_if(
parents.second->chromR[(startB - 1 + nOfMovedRoutes) % nOfRoutesB].begin(),
parents.second->chromR[(startB - 1 + nOfMovedRoutes) % nOfRoutesB].end(),
[&clientsInSelectedA](int c) { return clientsInSelectedA.find(c) != clientsInSelectedA.end(); })) -
static_cast<int>(std::count_if(
parents.second->chromR[(startB - 1 + nOfRoutesB) % nOfRoutesB].begin(),
parents.second->chromR[(startB - 1 + nOfRoutesB) % nOfRoutesB].end(),
[&clientsInSelectedA](int c) { return clientsInSelectedA.find(c) != clientsInSelectedA.end(); }));
const int differenceBLeft = countClientsIn(parents.second->chromR[idxBLastMoved], clientsInSelectedA) -
countClientsIn(parents.second->chromR[idxBLeft], clientsInSelectedA);

// Difference for moving 'right' in parent B
const int differenceBRight =
static_cast<int>(std::count_if(
parents.second->chromR[startB].begin(), parents.second->chromR[startB].end(),
[&clientsInSelectedA](int c) { return clientsInSelectedA.find(c) != clientsInSelectedA.end(); })) -
static_cast<int>(std::count_if(
parents.second->chromR[(startB + nOfMovedRoutes) % nOfRoutesB].begin(),
parents.second->chromR[(startB + nOfMovedRoutes) % nOfRoutesB].end(),
[&clientsInSelectedA](int c) { return clientsInSelectedA.find(c) != clientsInSelectedA.end(); }));
const int differenceBRight = countClientsIn(parents.second->chromR[startB], clientsInSelectedA) -
countClientsIn(parents.second->chromR[idxBRight], clientsInSelectedA);

const int bestDifference = std::min({differenceALeft, differenceARight, differenceBLeft, differenceBRight});

// Avoiding infinite loop by adding a guard in case nothing changes
if (bestDifference < 0) {
if (bestDifference == differenceALeft) {
for (int c : parents.first->chromR[(startA + nOfMovedRoutes - 1) % nOfRoutesA]) {
clientsInSelectedA.erase(clientsInSelectedA.find(c));
auto it = clientsInSelectedA.find(c);
if (it != clientsInSelectedA.end()) clientsInSelectedA.erase(it);
}
startA = (startA - 1 + nOfRoutesA) % nOfRoutesA;
for (int c : parents.first->chromR[startA]) { clientsInSelectedA.insert(c); }
} else if (bestDifference == differenceARight) {
for (int c : parents.first->chromR[startA]) { clientsInSelectedA.erase(clientsInSelectedA.find(c)); }
for (int c : parents.first->chromR[startA]) {
auto it = clientsInSelectedA.find(c);
if (it != clientsInSelectedA.end()) clientsInSelectedA.erase(it);
}
startA = (startA + 1) % nOfRoutesA;
for (int c : parents.first->chromR[(startA + nOfMovedRoutes - 1) % nOfRoutesA]) {
clientsInSelectedA.insert(c);
}
} else if (bestDifference == differenceBLeft) {
for (int c : parents.second->chromR[(startB + nOfMovedRoutes - 1) % nOfRoutesB]) {
clientsInSelectedB.erase(clientsInSelectedB.find(c));
auto it = clientsInSelectedB.find(c);
if (it != clientsInSelectedB.end()) clientsInSelectedB.erase(it);
}
startB = (startB - 1 + nOfRoutesB) % nOfRoutesB;
for (int c : parents.second->chromR[startB]) { clientsInSelectedB.insert(c); }
} else if (bestDifference == differenceBRight) {
for (int c : parents.second->chromR[startB]) { clientsInSelectedB.erase(clientsInSelectedB.find(c)); }
for (int c : parents.second->chromR[startB]) {
auto it = clientsInSelectedB.find(c);
if (it != clientsInSelectedB.end()) clientsInSelectedB.erase(it);
}
startB = (startB + 1) % nOfRoutesB;
for (int c : parents.second->chromR[(startB + nOfMovedRoutes - 1) % nOfRoutesB]) {
clientsInSelectedB.insert(c);
Expand Down
2 changes: 1 addition & 1 deletion third_party/hgs_vrptw/Individual.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct CostSol {
int nbRoutes; // Number of routes
int distance; // Total Distance
int capacityExcess; // Total excess load over all routes
int durationExcess; // Total excess duration over all routes
//int durationExcess; // Total excess duration over all routes
int waitTime; // Total wait time (time to wait to meet earliest possible arrival) over all routes
int timeWarp; // Total time warp (going back in time to meet latest possible arrival) over all routes
bool isFeasible; // Feasibility status of the individual
Expand Down
33 changes: 22 additions & 11 deletions third_party/hgs_vrptw/Split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,32 @@
#include "Individual.h"
#include "Params.h"
#include "Split.h"

void Split::generalSplit(Individual *indiv, int nbMaxVehicles) {
// Do not apply Split with fewer vehicles than the trivial (LP) bin packing bound
maxVehicles = std::max(nbMaxVehicles, static_cast<int>(std::ceil(params->totalDemand / params->vehicleCapacity)));

// Initialization of the data structures for the Linear Split algorithm
// Direct application of the code located at https://github.com/vidalt/Split-Library
// Pre-fetch some useful values
//const int nbClients = params->nbClients;

// Ensure vectors are resized properly to accommodate index 1 to nbClients
//cliSplit.resize(nbClients + 1); // cliSplit should be resized before access
//sumLoad.resize(nbClients + 1, 0);
//sumService.resize(nbClients + 1, 0);
//sumDistance.resize(nbClients + 1, 0);

// Loop over all clients, excluding the depot
for (int i = 1; i <= params->nbClients; i++) {
// Store all information on clientSplits (use chromT[i-1] since the depot is not included in chromT)
cliSplit[i].demand = params->cli[indiv->chromT[i - 1]].demand;
cliSplit[i].serviceTime = params->cli[indiv->chromT[i - 1]].serviceDuration;
cliSplit[i].d0_x = params->timeCost.get(0, indiv->chromT[i - 1]);
cliSplit[i].dx_0 = params->timeCost.get(indiv->chromT[i - 1], 0);
int chromIdx = indiv->chromT[i - 1];

// Store all information on clientSplits
cliSplit[i].demand = params->cli[chromIdx].demand;
cliSplit[i].serviceTime = params->cli[chromIdx].serviceDuration;
cliSplit[i].d0_x = params->timeCost.get(0, chromIdx);
cliSplit[i].dx_0 = params->timeCost.get(chromIdx, 0);

// The distance to the next client is INT_MIN for the last client
if (i < params->nbClients) {
cliSplit[i].dnext = params->timeCost.get(indiv->chromT[i - 1], indiv->chromT[i]);
cliSplit[i].dnext = params->timeCost.get(chromIdx, indiv->chromT[i]);
} else {
cliSplit[i].dnext = INT_MIN;
}
Expand All @@ -34,13 +42,16 @@ void Split::generalSplit(Individual *indiv, int nbMaxVehicles) {
sumDistance[i] = sumDistance[i - 1] + cliSplit[i - 1].dnext;
}

// We first try the Simple Split, and then the Split with Limited Fleet if this is not successful
if (splitSimple(indiv) == 0) { splitLF(indiv); }
// Try Simple Split, then fall back to Split with Limited Fleet if needed
if (splitSimple(indiv) == 0) {
splitLF(indiv);
}

// Build up the rest of the Individual structure
indiv->evaluateCompleteCost();
}


int Split::splitSimple(Individual *indiv) {
// Reinitialize the potential structure
potential[0][0] = 0;
Expand Down

0 comments on commit a0c30d1

Please sign in to comment.