Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • a24jacqb/pdptw-main
1 result
Show changes
Commits on Source (2)
  • awenjb's avatar
    Clean code · 32dda218
    awenjb authored
    - replace all [ . ] by .at( . )  when looking into a vector
    32dda218
  • awenjb's avatar
    add output and simple visualisation · b758be1b
    awenjb authored
    - add simple solution exporter (to json)
    - add jupyter visualisation (map only)
    b758be1b
Showing
with 775 additions and 85 deletions
......@@ -34,6 +34,7 @@ add_executable(pdptw src/mains/main.cpp
src/lns/modification/route/insert_route.cpp
src/lns/modification/route/remove_route.cpp
src/output/solution_checker.cpp
src/output/solution_exporter.cpp
src/lns/operators/sorting_strategy.cpp
src/lns/operators/destruction/random_destroy.cpp
src/lns/operators/generators/enumerate.cpp
......
import json
import datetime
import enum
import folium
import numpy as np
import pandas as pd
import osmnx as ox
import networkx as nx
def read_json(file):
try:
with open(file, 'r') as file:
data = json.load(file)
return data
except FileNotFoundError:
print(f"Error : The file {file} does not exist.")
except json.JSONDecodeError:
print(f"Error : The file {file} is not a valid JSON file.")
except Exception as e:
print(f"Error : {e}")
G_drive = ox.graph_from_point((47.213811, -1.553168), dist=10000,
network_type='bike')
class PDPTWSolution:
def __init__(self, filename: str):
with open(filename, mode="r", encoding="utf-8") as f:
self._json_file = json.load(f)
self._parse_json()
def _parse_json(self):
if self._json_file is None:
raise "Trying to parse json, but was not loaded"
self._routes: list[dict] = self._json_file["routes"]
def get_routes(self):
return self._routes
def get_json(self):
return self._json_file
class PDPTWData:
def __init__(self, filename: str):
with open(filename, mode="r", encoding="utf-8") as f:
self._json_file = json.load(f)
self._parse_json()
def _parse_json(self):
if self._json_file is None:
raise "Trying to parse json, but was not loaded"
self._locations: list[dict] = self._json_file["locations"]
self._depot: list[dict] = self._json_file["depot"]
self._capacity = self._json_file["capacity"]
def get_depot(self):
return self._depot
def get_locations(self):
return self._locations
def get_capacity(self):
return self._capacity
def get_json(self):
return self._json_file
def get_route_as_dataframe(data: PDPTWData, solution: PDPTWSolution, route_index:int) -> pd.DataFrame:
route_df=pd.DataFrame()
route_ids = solution.get_routes()[route_index]["locationIDs"]
for id in route_ids:
line = {"route": route_index,
"location": id,
"type": data.get_locations()[id - 1]["locType"],
"latitude": data.get_locations()[id - 1]["latitude"],
"longitude": data.get_locations()[id - 1]["longitude"]}
route_df = pd.concat([route_df, pd.DataFrame.from_dict([line])], ignore_index=True)
return route_df
def display_points_of_interest(map: folium.Map, data: PDPTWData):
folium.Marker(location=[data.get_depot()["latitude"], data.get_depot()["longitude"]],
icon=folium.Icon(color="red", popup="DEPOT")).add_to(map)
for location in data.get_locations():
if location["locType"] == "PICKUP":
color = "darkblue"
text = "pickup"
elif location["locType"] == "DELIVERY":
color = "lightblue"
text = "delivery"
else:
continue
folium.Marker(location=[location["latitude"], location["longitude"]],
icon=folium.Icon(color=color, popup=text)).add_to(map)
def display_route(map: folium.Map, data: PDPTWData, solution: PDPTWSolution, route_index: int, color: str="red"):
df = get_route_as_dataframe(data, solution, route_index)
# add depot at the begining and the end
types = ["DEPOT"] + list(df["type"]) + ["DEPOT"]
depot_coord = (data.get_depot()["latitude"], data.get_depot()["longitude"])
locations = [depot_coord] + list(zip(df["latitude"], df["longitude"])) + [depot_coord]
real_path_locations = []
network_locations = ox.nearest_nodes(G_drive,
[data.get_depot()["longitude"]] + list(df["longitude"]) + [data.get_depot()["longitude"]],
[data.get_depot()["latitude"]] + list(df["latitude"]) + [data.get_depot()["latitude"]])
for i in range(1, len(locations)):
edge = [network_locations[i - 1], network_locations[i]]
real_nodes = ox.shortest_path(G_drive, edge[0], edge[1], weight="length")
if real_nodes is not None:
long_lat_edges = []
for node in real_nodes:
g_drive_node = G_drive.nodes[node]
if "x" in g_drive_node and "y" in g_drive_node:
long_lat_edges.append((g_drive_node["y"], g_drive_node["x"]))
real_path_locations.extend(long_lat_edges)
else:
real_path_locations.append(locations[i])
folium.PolyLine(real_path_locations, color=color, weight=5, opacity=0.5, smooth_factor=0).add_to(map)
for index, row in df.iterrows():
if row["type"] == "REQUEST":
text = f'{index} - {row["latitude"], row["longitude"]} : times ({row["arrival"]},{row["service"]},{row["departure"]}), time window [{row["Hmin"]},{row["Hmax"]}]'
folium.Circle(location=(row["latitude"], row["longitude"]), fill_color="orange", radius=4,
tooltip=text).add_to(map)
This diff is collapsed.
......@@ -6,7 +6,7 @@ double data::addedCostForInsertion(PDPTWData const &data, int before, int toInse
{
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][toInsert] + matrix[toInsert][after] - matrix[before][after];
cost = matrix.at(before).at(toInsert) + matrix.at(toInsert).at(after) - matrix.at(before).at(after);
return cost;
}
......@@ -15,7 +15,7 @@ double data::removedCostForSuppression(PDPTWData const &data, int before, int to
const Matrix & matrix = data.getMatrix();
double cost = 0;
cost = matrix[before][after] - matrix[before][toRemove] - matrix[toRemove][after];
cost = matrix.at(before).at(after) - matrix.at(before).at(toRemove) - matrix.at(toRemove).at(after);
return cost;
}
......@@ -31,28 +31,28 @@ double data::routeCost(PDPTWData const & data, Route const & route)
return 0;
}
// cost from and to the depot
cost += matrix[0][routeIDs.at(0)];
//std::cout << "\n route cost : " << matrix[0][routeIDs[0]] << " ";
cost += matrix[routeIDs.back()][0];
cost += matrix.at(0).at(routeIDs.at(0));
//std::cout << "\n route cost : " << matrix.at(0).at(routeIDs.at(0) << " ";
cost += matrix.at(routeIDs.back()).at(0);
// cost in the route
for (size_t i = 0; i < routeIDs.size() - 1; ++i) {
cost += matrix[routeIDs[i]][routeIDs[i+1]];
//std::cout << matrix[routeIDs[i]][routeIDs[i+1]] << " ";
cost += matrix.at(routeIDs.at(i)).at(routeIDs.at(i+1));
//std::cout << matrix.at(routeIDs.at(i).at(routeIDs.at(i+1) << " ";
}
//std::cout << matrix[routeIDs.back()][0] << " : " << cost << "\n";
//std::cout << matrix.at(routeIDs.back()).at(0) << " : " << cost << "\n";
return cost;
}
double data::TravelCost(PDPTWData const &data, int from, int to)
{
return data.getMatrix()[from][to];
return data.getMatrix().at(from).at(to);
}
double data::TravelTime(PDPTWData const &data, int from, int to)
{
return data.getMatrix()[from][to];
return data.getMatrix().at(from).at(to);
}
......
......@@ -4,19 +4,18 @@
#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
#include <utility>
// spdlog repris du code lns-framework mais pas utilisé ici -> TODO
namespace fs = std::filesystem;
using json = nlohmann::json;
bool checkFilePresence(std::string &filepath)
{
return fs::is_regular_file(filepath);
}
PDPTWData parsing::parseJson(std::string filepath)
{
if (!checkFilePresence(filepath))
......@@ -24,6 +23,7 @@ PDPTWData parsing::parseJson(std::string filepath)
spdlog::error("Data file \"{}\" does not exist", filepath);
exit(1);
}
std::ifstream jsonFile(filepath);
if (!jsonFile.is_open())
......@@ -35,11 +35,22 @@ PDPTWData parsing::parseJson(std::string filepath)
try
{
// extract filename (data name)
size_t pos = filepath.find_last_of("/\\");
std::string filename = (pos != std::string::npos) ? filepath.substr(pos + 1) : filepath;
size_t dotPos = filename.find_last_of('.');
if (dotPos != std::string::npos)
{
filename = filename.substr(0, dotPos);
}
// generate PDPTWData
json j;
jsonFile >> j;
return json_to_data(j);
}
catch (std::exception const &e)// catching all exceptions to properly log the error and quit gracefully
return json_to_data(filename, j);
} catch (std::exception const &e)// catching all exceptions to properly log the error and quit gracefully
{
spdlog::error("Error while parsing the input json:");
spdlog::error("{}", e.what());
......@@ -48,46 +59,41 @@ PDPTWData parsing::parseJson(std::string filepath)
}
}
PDPTWData json_to_data(const json& j)
PDPTWData json_to_data(std::string dataName, json const &j)
{
int size = j.at("size").get<int>();
int capacity = j.at("capacity").get<int>();
auto depot_json = j.at("depot");
TimeWindow tw(depot_json.at("timeWindow").at(0), depot_json.at("timeWindow").at(1));
Location depot(
0,
depot_json.at("longitude"),
depot_json.at("latitude"),
0,
tw,
depot_json.at("serviceDuration"),
0,
LocType::DEPOT
);
Location depot(0,
depot_json.at("longitude"),
depot_json.at("latitude"),
0,
tw,
depot_json.at("serviceDuration"),
0,
LocType::DEPOT);
std::vector<Location> locations;
for (const auto& loc : j.at("locations"))
for (auto const &loc: j.at("locations"))
{
LocType loc_type = (loc.at("locType") == "PICKUP") ? LocType::PICKUP : LocType::DELIVERY;
TimeWindow loc_tw(loc.at("timeWindow").at(0), loc.at("timeWindow").at(1));
locations.emplace_back(
loc.at("id"),
loc.at("longitude"),
loc.at("latitude"),
loc.at("demand"),
loc_tw,
loc.at("serviceDuration"),
loc.at("pairedLocation"),
loc_type
);
locations.emplace_back(loc.at("id"),
loc.at("longitude"),
loc.at("latitude"),
loc.at("demand"),
loc_tw,
loc.at("serviceDuration"),
loc.at("pairedLocation"),
loc_type);
}
Matrix distance_matrix = j.at("distance_matrix").get<Matrix>();
return {size, capacity, depot, locations, distance_matrix};
return {std::move(dataName), size, capacity, depot, locations, distance_matrix};
}
......@@ -10,4 +10,4 @@ namespace parsing
PDPTWData parseJson(std::string filepath);
}
PDPTWData json_to_data(const json& j);
\ No newline at end of file
PDPTWData json_to_data(std::string dataName, const json& j);
\ No newline at end of file
......@@ -30,6 +30,11 @@ Location const &PDPTWData::getDepot() const
return depot;
}
std::string PDPTWData::getDataName() const
{
return dataName;
}
Location const &PDPTWData::getLocation(int id) const
{
if (id==0)
......@@ -45,8 +50,8 @@ Matrix const &PDPTWData::getMatrix() const
return distanceMatrix;
}
PDPTWData::PDPTWData(int size, int capacity, Location depot, std::vector<Location> locations, Matrix distanceMatrix)
: size(size), capacity(capacity), depot(depot), locations(std::move(locations)), distanceMatrix(std::move(distanceMatrix))
PDPTWData::PDPTWData(std::string dataName, int size, int capacity, Location depot, std::vector<Location> locations, Matrix distanceMatrix)
: dataName(dataName), size(size), capacity(capacity), depot(depot), locations(std::move(locations)), distanceMatrix(std::move(distanceMatrix))
{
// Associate pair of locations
pairs.clear();
......@@ -55,7 +60,7 @@ PDPTWData::PDPTWData(int size, int capacity, Location depot, std::vector<Locatio
if( loc.getLocType() == LocType::PICKUP )
{
// vector indexed from 0 / Location indexed from 1
pairs.emplace_back(loc, this->locations[loc.getPair()-1], loc.getId());
pairs.emplace_back(loc, this->locations.at(loc.getPair()-1), loc.getId());
}
}
}
......@@ -75,6 +80,7 @@ const Pair &PDPTWData::getPair(int id) const
void PDPTWData::print() const
{
std::cout << "Instance name : " << dataName << "\n";
std::cout << "Instance size: " << size << "\n";
std::cout << "Capacity: " << capacity << "\n";
std::cout << "Depot:\n";
......@@ -135,7 +141,7 @@ bool PDPTWData::checkMatrix() const
{
for (int k = 0; k < size; k++)
{
if (getMatrix()[i][j] > getMatrix()[i][k] + getMatrix()[k][j])
if (getMatrix().at(i).at(j) > getMatrix().at(i).at(k) + getMatrix().at(k).at(j))
{
return true;
}
......@@ -152,7 +158,7 @@ bool PDPTWData::checkLocation() const
// check if location id equals the position in the location vector
for (size_t i = 0; i < size-1; ++i) {
if (locations[i].getId() != static_cast<int>(i)+1) {
if (locations.at(i).getId() != static_cast<int>(i)+1) {
return true;
}
}
......@@ -162,9 +168,9 @@ bool PDPTWData::checkLocation() const
{
if (loc.getLocType() == LocType::PICKUP)
{
if ( (getLocations()[loc.getPair()-1].getLocType() != LocType::DELIVERY)
|| (loc.getDemand() != - getLocations()[loc.getPair()-1].getDemand())
|| (loc.getId() != getLocations()[loc.getPair()-1].getPair()) )
if ( (getLocations().at(loc.getPair()-1).getLocType() != LocType::DELIVERY)
|| (loc.getDemand() != - getLocations().at(loc.getPair()-1).getDemand())
|| (loc.getId() != getLocations().at(loc.getPair()-1).getPair()) )
{
return true;
}
......
......@@ -23,6 +23,7 @@ public:
class PDPTWData
{
std::string dataName;
int size;
int capacity;
Location depot;
......@@ -42,7 +43,7 @@ public:
* Constructs an empty PDPTWData.
* @see parsing::parseJson
*/
PDPTWData(int size, int capacity, Location depot, std::vector<Location> locations, Matrix distanceMatrix);
PDPTWData(std::string dataName, int size, int capacity, Location depot, std::vector<Location> locations, Matrix distanceMatrix);
/**
* Checks some data coherence
*/
......@@ -67,6 +68,6 @@ public:
int getSize() const;
int getCapacity() const;
std::string getDataName() const;
void print() const;
};
......@@ -36,7 +36,7 @@ void CapacityConstraint::initCapacities()
std::vector<int> const & CapacityConstraint::getRouteCapacities(int routeIndex) const
{
return routeCapacities[routeIndex];
return routeCapacities.at(routeIndex);
}
// check for every location between the pickupPosition and the deliveryPosition
......@@ -69,33 +69,33 @@ void CapacityConstraint::applyModif(Pair const &pair, int routeIndex, int Pickup
if (addPair)
{
// Insert new values
routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+DeliveryPosition, 0);
routeCapacities.at(routeIndex).insert(routeCapacities.at(routeIndex).begin()+DeliveryPosition, 0);
if (DeliveryPosition != 0)
{
routeCapacities[routeIndex][DeliveryPosition] += routeCapacities[routeIndex][DeliveryPosition-1];
routeCapacities.at(routeIndex).at(DeliveryPosition) += routeCapacities.at(routeIndex).at(DeliveryPosition-1);
}
routeCapacities[routeIndex].insert(routeCapacities[routeIndex].begin()+PickupPosition, pair.getPickup().getDemand());
routeCapacities.at(routeIndex).insert(routeCapacities.at(routeIndex).begin()+PickupPosition, pair.getPickup().getDemand());
if (PickupPosition != 0)
{
routeCapacities[routeIndex][PickupPosition] += routeCapacities[routeIndex][PickupPosition-1];
routeCapacities.at(routeIndex).at(PickupPosition) += routeCapacities.at(routeIndex).at(PickupPosition-1);
}
// Update value
for (int i = PickupPosition + 1; i < DeliveryPosition + 1; ++i)
{
routeCapacities[routeIndex][i] += pair.getPickup().getDemand();
routeCapacities.at(routeIndex).at(i) += pair.getPickup().getDemand();
}
}
else
{
for (int i = PickupPosition + 1; i < DeliveryPosition; ++i)
{
routeCapacities[routeIndex][i] += pair.getDelivery().getDemand();
routeCapacities.at(routeIndex).at(i) += pair.getDelivery().getDemand();
}
// remove pair
routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + DeliveryPosition);
routeCapacities[routeIndex].erase(routeCapacities[routeIndex].begin() + PickupPosition);
routeCapacities.at(routeIndex).erase(routeCapacities.at(routeIndex).begin() + DeliveryPosition);
routeCapacities.at(routeIndex).erase(routeCapacities.at(routeIndex).begin() + PickupPosition);
}
}
......
......@@ -31,15 +31,15 @@ void TimeWindowConstraint::computeReachTimes(const PDPTWData& data, const std::v
// Adjust the size of reachTimes vector
reachTimes.resize(routeIDs.size(), 0);
// Time to the first location
reachTimes[0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
reachTimes.at(0) = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Compute other reachTimes (max between arrival and start of the time window + previous service time + travel time)
for (int i = 1; i < routeIDs.size(); ++i) {
TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i));
// locations are indexed from 0 to n-1,
TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs[i - 1]).getTimeWindow().getStart();
TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs.at(i - 1)).getTimeWindow().getStart();
reachTimes[i] = std::max(reachTimes[i - 1], startTW) + serviceTime + travelTime;
reachTimes.at(i) = std::max(reachTimes.at(i - 1), startTW) + serviceTime + travelTime;
}
}
......@@ -96,7 +96,7 @@ bool TimeWindowConstraint::checkInsertion(const PDPTWData& data, const Pair & pa
// Check Time Windows
for (int i = 0; i < newReachTimes.size(); ++i)
{
if (! data.getLocation(route[i]).getTimeWindow().isValid(newReachTimes.at(i)) )
if (! data.getLocation(route.at(i)).getTimeWindow().isValid(newReachTimes.at(i)) )
{
return false;
}
......@@ -124,15 +124,15 @@ void TimeWindowConstraint::ApplyModif(const PDPTWData& data, const Pair & pair,
}
// Adjust the size of reachTimes vector
allRouteReachTimes[routeIndex].resize(routeIDs.size(), 0);
allRouteReachTimes.at(routeIndex).resize(routeIDs.size(), 0);
// Time to the first location
allRouteReachTimes[routeIndex][0] = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
allRouteReachTimes.at(routeIndex).at(0) = data.getDepot().getTimeWindow().getStart() + data::TravelTime(data, 0, routeIDs.at(0));
// Compute other reachTimes (max between arrival and start of the time window)
for (int i = 1; i < routeIDs.size(); ++i) {
TimeInteger travelTime = data::TravelTime(data, routeIDs[i - 1], routeIDs[i]);
TimeInteger serviceTime = data.getLocation(routeIDs[i - 1]).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs[i - 1]).getTimeWindow().getStart();
allRouteReachTimes[routeIndex][i] = std::max(allRouteReachTimes[routeIndex][i - 1], startTW) + serviceTime + travelTime;
TimeInteger travelTime = data::TravelTime(data, routeIDs.at(i - 1), routeIDs.at(i));
TimeInteger serviceTime = data.getLocation(routeIDs.at(i - 1)).getServiceDuration();
TimeInteger startTW = data.getLocation(routeIDs.at(i - 1)).getTimeWindow().getStart();
allRouteReachTimes.at(routeIndex).at(i) = std::max(allRouteReachTimes.at(routeIndex).at(i - 1), startTW) + serviceTime + travelTime;
}
}
......
......@@ -34,8 +34,8 @@ double InsertPair::evaluate(Solution const &solution) const {
const std::vector<int> & routeIDs = route.getRoute();
const PDPTWData &data = solution.getData();
int prevPickup = (pickupInsertion == 0) ? 0 : routeIDs[pickupInsertion - 1];
int nextPickup = (pickupInsertion >= routeIDs.size()) ? 0 : routeIDs[pickupInsertion];
int prevPickup = (pickupInsertion == 0) ? 0 : routeIDs.at(pickupInsertion - 1);
int nextPickup = (pickupInsertion >= routeIDs.size()) ? 0 : routeIDs.at(pickupInsertion);
double pickupCost = data::addedCostForInsertion(data, prevPickup, pickupLocation.getId(), nextPickup);
......@@ -43,12 +43,12 @@ double InsertPair::evaluate(Solution const &solution) const {
// the insertion of the delivery is done just after the pickup without intermediate location
// otherwise, the pickup and the delivery insertion are independant and the pickup insertion does not affect the delivery insertion cost
int prevDelivery = (deliveryInsertion == 0) ? 0 : routeIDs[deliveryInsertion - 1];
int prevDelivery = (deliveryInsertion == 0) ? 0 : routeIDs.at(deliveryInsertion - 1);
if (pickupInsertion == deliveryInsertion)
{
prevDelivery = pickupLocation.getId();
}
int nextDelivery = (deliveryInsertion >= routeIDs.size()) ? 0 : routeIDs[deliveryInsertion];
int nextDelivery = (deliveryInsertion >= routeIDs.size()) ? 0 : routeIDs.at(deliveryInsertion);
//std::cout << "insert " << prevDelivery << " + " << deliveryLocation.getId() << " + " << nextDelivery << "\n";
double deliveryCost = data::addedCostForInsertion(data, prevDelivery, deliveryLocation.getId(), nextDelivery);
......
......@@ -18,7 +18,7 @@ void RemovePair::modifySolution(Solution &solution)
// update removedPairID
removedPairID.push_back(route.getRoute()[pickupDeletion]);
removedPairID.push_back(route.getRoute().at(pickupDeletion));
// remove the delivery before (to not have to update the index)
route.deleteAt(deliveryDeletion);
......@@ -31,14 +31,14 @@ double RemovePair::evaluate(Solution const &solution) const
std::vector<int> const &routeIDs = route.getRoute();
PDPTWData const &data = solution.getData();
int prevPickup = (pickupDeletion == 0) ? 0 : routeIDs[pickupDeletion - 1];
int prevPickup = (pickupDeletion == 0) ? 0 : routeIDs.at(pickupDeletion - 1);
// pickup location should not be at the end of a route anyway
int nextPickup = (pickupDeletion >= routeIDs.size()) ? 0 : routeIDs[pickupDeletion + 1];
int nextPickup = (pickupDeletion >= routeIDs.size()) ? 0 : routeIDs.at(pickupDeletion + 1);
double pickupCost = data::removedCostForSuppression(data, prevPickup, pickupLocation.getId(), nextPickup);
int prevDelivery = (deliveryDeletion == 0) ? 0 : routeIDs[deliveryDeletion - 1];
int nextDelivery = (deliveryDeletion >= routeIDs.size()) ? 0 : routeIDs[deliveryDeletion + 1];
int prevDelivery = (deliveryDeletion == 0) ? 0 : routeIDs.at(deliveryDeletion - 1);
int nextDelivery = (deliveryDeletion >= routeIDs.size()) ? 0 : routeIDs.at(deliveryDeletion + 1);
if (deliveryDeletion == pickupDeletion + 1)
{
prevDelivery = prevPickup;
......
......@@ -52,7 +52,7 @@ int Route::getLocation(int index) const
spdlog::error("Invalid index when reading route: {}", index);
throw std::out_of_range("Invalid index when reading route");
}
return route[index];
return route.at(index);
}
......
......@@ -112,7 +112,7 @@ Route &Solution::getRoute(int routeIndex)
spdlog::error("Invalid route index: {}", routeIndex);
throw std::out_of_range("Invalid route index.");
}
return routes[routeIndex];
return routes.at(routeIndex);
}
Route const &Solution::getRoute(int routeIndex) const
......@@ -122,7 +122,7 @@ Route const &Solution::getRoute(int routeIndex) const
spdlog::error("Invalid route index: {}", routeIndex);
throw std::out_of_range("Invalid route index.");
}
return routes[routeIndex];
return routes.at(routeIndex);
}
double Solution::getCost() const
......
......@@ -25,6 +25,7 @@
#include "lns/operators/generators/modification_generator.h"
#include "lns/operators/sorting_strategy.h"
#include "output/solution_exporter.h"
using json = nlohmann::json;
......@@ -82,5 +83,7 @@ int main(int argc, char const *argv[])
operatorInstance.reconstructSolution(solution, blinkRate);
solution.print();
output::exportToJson(solution);
return 0;
}
#include "solution_exporter.h"
std::string getCurrentDate()
{
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
char buffer[11];// "DD-MM-YYYY" + null terminator
std::strftime(buffer, sizeof(buffer), "%d-%m-%Y", &tm);
return std::string(buffer);
}
nlohmann::ordered_json output::getMinimalJson(Solution const &solution)
{
nlohmann::ordered_json jsonSolution;
nlohmann::ordered_json jsonRoutes = nlohmann::ordered_json::array();
int routeID = 0;
for (auto const &route: solution.getRoutes())
{
jsonRoutes.push_back(routeToJson(routeID, route));
++routeID;
}
jsonSolution["InstanceName"] = solution.getData().getDataName();
jsonSolution["Authors"] = "...";
jsonSolution["Date"] = getCurrentDate();
jsonSolution["Reference"] = "...";
jsonSolution["routes"] = jsonRoutes;
return jsonSolution;
}
nlohmann::ordered_json output::getCompleteJson(Solution const &solution)
{
nlohmann::ordered_json jsonSolution;
// TO DO
return jsonSolution;
}
void output::exportToJson(Solution const &solution)
{
std::string directory = "./../../output";
std::string filename = directory + "/" + solution.getData().getDataName() + "_sol.json";
if (!std::filesystem::exists(directory))
{
std::filesystem::create_directory(directory);
}
std::ofstream file(filename);
if (!file)
{
spdlog::error("Error when opening the file {}", filename);
exit(1);
return;
}
nlohmann::ordered_json jsonData = output::getMinimalJson(solution);
file << jsonData.dump();
file.close();
std::cout << "Solution exported" << std::endl;
}
nlohmann::ordered_json output::routeToJson(int routeID, Route const &route)
{
return nlohmann::ordered_json{{"routeID", routeID}, {"locationIDs", route.getRoute()}};
}
#pragma once
#include "lns/solution/solution.h"
#include <nlohmann/json.hpp>
#include <ctime>
#include <fstream>
namespace output
{
/**
* Get a json representation of a solution with the same info as in the benchmarks results (Li&Lim, Sartori&Buriol)
*/
nlohmann::ordered_json getMinimalJson(Solution const &solution);
/**
* Get a complete json representation of a solution (heavier)
*/
nlohmann::ordered_json getCompleteJson(Solution const &solution);
nlohmann::ordered_json routeToJson(int routeID, const Route& route);
void exportToJson(Solution const &solution);
}// namespace output
std::string getCurrentDate();
\ No newline at end of file