Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion benchmark/Bench_Network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,42 @@
}
}
}
static void BM_RoadNetwork_ShortestPath(benchmark::State& state) {
static void BM_RoadNetwork_AllPathsTo(benchmark::State& state) {

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const

Check warning

Code scanning / Cppcheck (reported by Codacy)

Parameter 'state' can be declared with const Warning test

Parameter 'state' can be declared with const
dsf::mobility::RoadNetwork network;
network.importEdges((DATA_FOLDER / "forlì_edges.csv").string());
network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string());
auto itNode = network.nodes().cbegin();
for (auto _ : state) {
auto paths = network.allPathsTo(itNode->first,
[](auto const& pEdge) { return pEdge->length(); });

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note test

MISRA 15.5 rule
++itNode;
}
}
static void BM_RoadNetwork_ShortestPath(benchmark::State& state) {
dsf::mobility::RoadNetwork network;
network.importEdges((DATA_FOLDER / "forlì_edges.csv").string());
network.importNodeProperties((DATA_FOLDER / "forlì_nodes.csv").string());
auto itSource = network.nodes().cbegin();
auto itTarget = std::next(network.nodes().cbegin(), network.nodes().size() / 2);
for (auto _ : state) {
auto path = network.shortestPath(itSource->first,
itTarget->first,
[](auto const& pEdge) { return pEdge->length(); });
benchmark::DoNotOptimize(path);
++itSource;
++itTarget;
if (itTarget == network.nodes().cend()) {
itTarget = network.nodes().cbegin();
}
}
}
BENCHMARK(BM_RoadNetwork_AddNode);
BENCHMARK(BM_RoadNetwork_AddEdge);
BENCHMARK(BM_RoadNetwork_CSVImport);
BENCHMARK(BM_RoadNetwork_GeoJSONImport);
BENCHMARK(BM_RoadNetwork_NodesLooping);
BENCHMARK(BM_RoadNetwork_EdgesLooping);
BENCHMARK(BM_RoadNetwork_ShortestPath);
BENCHMARK(BM_RoadNetwork_AllPathsTo);

BENCHMARK_MAIN();
99 changes: 98 additions & 1 deletion src/dsf/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,104 @@
&dsf::mobility::RoadNetwork::addCoil,
pybind11::arg("streetId"),
pybind11::arg("name") = std::string(),
dsf::g_docstrings.at("dsf::mobility::RoadNetwork::addCoil").c_str());
dsf::g_docstrings.at("dsf::mobility::RoadNetwork::addCoil").c_str())
.def(
"shortestPath",
[](const dsf::mobility::RoadNetwork& self,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
dsf::Id sourceId,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
dsf::Id targetId,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
dsf::PathWeight weightFunction,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
double threshold) {
return self.shortestPath(

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
sourceId,
targetId,
[weightFunction](const std::unique_ptr<dsf::mobility::Street>& street) {
switch (weightFunction) {
case dsf::PathWeight::LENGTH:
return street->length();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
case dsf::PathWeight::TRAVELTIME:
return street->length() / street->maxSpeed();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
case dsf::PathWeight::WEIGHT:
return street->weight();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
default:
return street->length() / street->maxSpeed();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
}
},
threshold);
},
pybind11::arg("sourceId"),
pybind11::arg("targetId"),
pybind11::arg("weightFunction") = dsf::PathWeight::TRAVELTIME,
pybind11::arg("threshold") = 1e-9,
"Find the shortest path between two nodes using Dijkstra's algorithm.\n\n"
"Args:\n"
" sourceId (int): The id of the source node\n"
" targetId (int): The id of the target node\n"
" weightFunction (PathWeight): The weight function to use (LENGTH, "
"TRAVELTIME, or WEIGHT)\n"
" threshold (float): A threshold value to consider alternative paths\n\n"
"Returns:\n"
" PathCollection: A map where each key is a node id and the value is a "
"vector of next hop node ids toward the target");

pybind11::class_<dsf::mobility::PathCollection>(mobility, "PathCollection")
.def(pybind11::init<>(), "Create an empty PathCollection")
.def(
"__getitem__",
[](const dsf::mobility::PathCollection& self, dsf::Id key) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 13.1 rule Note

MISRA 13.1 rule
auto it = self.find(key);
if (it == self.end()) {
throw pybind11::key_error("Key not found");
}
return it->second;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
},
pybind11::arg("key"),
"Get the next hops for a given node id")
.def(
"__setitem__",
[](dsf::mobility::PathCollection& self,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
dsf::Id key,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
std::vector<dsf::Id> value) { self[key] = value; },
pybind11::arg("key"),
pybind11::arg("value"),
"Set the next hops for a given node id")
.def(
"__contains__",
[](const dsf::mobility::PathCollection& self, dsf::Id key) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
return self.find(key) != self.end();

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
},
pybind11::arg("key"),
"Check if a node id exists in the collection")
.def(
"__len__",
[](const dsf::mobility::PathCollection& self) { return self.size(); },

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
"Get the number of nodes in the collection")
.def(
"keys",
[](const dsf::mobility::PathCollection& self) {
std::vector<dsf::Id> keys;
keys.reserve(self.size());
for (const auto& [key, _] : self) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
keys.push_back(key);
}
return keys;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
},
"Get all node ids in the collection")
.def(
"items",
[](const dsf::mobility::PathCollection& self) {
pybind11::dict items;
for (const auto& [key, value] : self) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
items[pybind11::int_(key)] = pybind11::cast(value);
}
return items;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
},
"Get all items (node id, next hops) in the collection")
.def("explode",
&dsf::mobility::PathCollection::explode,
pybind11::arg("sourceId"),
pybind11::arg("targetId"),
dsf::g_docstrings.at("dsf::mobility::PathCollection::explode").c_str());

pybind11::class_<dsf::mobility::Itinerary>(mobility, "Itinerary")
.def(pybind11::init<dsf::Id, dsf::Id>(),
Expand Down
2 changes: 1 addition & 1 deletion src/dsf/dsf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

static constexpr uint8_t DSF_VERSION_MAJOR = 4;
static constexpr uint8_t DSF_VERSION_MINOR = 4;
static constexpr uint8_t DSF_VERSION_PATCH = 0;
static constexpr uint8_t DSF_VERSION_PATCH = 1;

static auto const DSF_VERSION =
std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH);
Expand Down
8 changes: 3 additions & 5 deletions src/dsf/mobility/Itinerary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ namespace dsf::mobility {
inFile.close();
}

void Itinerary::setPath(std::unordered_map<Id, std::vector<Id>> path) {
m_path = std::move(path);
void Itinerary::setPath(PathCollection pathCollection) {
m_path = std::move(pathCollection);
}

Id Itinerary::id() const { return m_id; }
Id Itinerary::destination() const { return m_destination; }
std::unordered_map<Id, std::vector<Id>> const& Itinerary::path() const {
return m_path;
}
PathCollection const& Itinerary::path() const { return m_path; }
void Itinerary::save(const std::string& fileName) const {
// Open binary file
std::ofstream outFile{fileName, std::ios::binary};
Expand Down
14 changes: 8 additions & 6 deletions src/dsf/mobility/Itinerary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#pragma once

#include "PathCollection.hpp"
#include "../utility/Typedef.hpp"

#include <concepts>
Expand All @@ -25,7 +26,7 @@ namespace dsf::mobility {
private:
Id m_id;
Id m_destination;
std::unordered_map<Id, std::vector<Id>> m_path;
PathCollection m_path;

public:
/// @brief Construct a new Itinerary object
Expand All @@ -42,8 +43,8 @@ namespace dsf::mobility {
void load(const std::string& fileName);

/// @brief Set the itinerary's path
/// @param path An adjacency matrix made by a SparseMatrix representing the itinerary's path
void setPath(std::unordered_map<Id, std::vector<Id>> path);
/// @param pathCollection A dsf::mobility::PathCollection representing all equivalent paths to the destination
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameter name mismatch in documentation. The documentation refers to @param pathCollection but the actual parameter name is path. The documentation should be updated to @param path to match the function signature.

Suggested change
/// @param pathCollection A dsf::mobility::PathCollection representing all equivalent paths to the destination
/// @param path A dsf::mobility::PathCollection representing all equivalent paths to the destination

Copilot uses AI. Check for mistakes.
void setPath(PathCollection pathCollection);

/// @brief Get the itinerary's id
/// @return Id, The itinerary's id
Expand All @@ -52,9 +53,10 @@ namespace dsf::mobility {
/// @return Id, The itinerary's destination
Id destination() const;
/// @brief Get the itinerary's path
/// @return std::unordered_map<Id, std::vector<Id>> const&, The itinerary's path
std::unordered_map<Id, std::vector<Id>> const& path() const;

/// @return PathCollection const&, The itinerary's path
PathCollection const& path() const;
/// @brief Save the itinerary to a binary file
/// @param fileName The name of the file to save the itinerary to
void save(const std::string& fileName) const;
};
}; // namespace dsf::mobility
39 changes: 39 additions & 0 deletions src/dsf/mobility/PathCollection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "PathCollection.hpp"

std::list<std::vector<dsf::Id>> dsf::mobility::PathCollection::explode(
Id const sourceId, Id const targetId) const {
std::list<std::vector<Id>> paths;

// Base case: if source equals target, return a path with just the source
if (sourceId == targetId) {
paths.push_back({sourceId});
return paths;

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
}

// Check if sourceId exists in the map
auto it = this->find(sourceId);
if (it == this->end()) {
return paths; // No paths available from this source

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 15.5 rule Note

MISRA 15.5 rule
}

auto const& nextHops = it->second;

// For each possible next hop from sourceId
for (auto const& hop : nextHops) {
if (hop == targetId) {
// Direct path found
paths.push_back({sourceId, targetId});
} else {
// Recursively find paths from hop to target
auto subPaths = explode(hop, targetId);

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 17.2 rule Note

MISRA 17.2 rule

// Prepend sourceId to each sub-path
for (auto& subPath : subPaths) {
subPath.insert(subPath.begin(), sourceId);
paths.push_back(std::move(subPath));
}
}
}

return paths;
}
20 changes: 20 additions & 0 deletions src/dsf/mobility/PathCollection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

#include "../utility/Typedef.hpp"

#include <list>
#include <unordered_map>
#include <vector>

namespace dsf::mobility {
class PathCollection : public std::unordered_map<Id, std::vector<Id>> {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
public:
using std::unordered_map<Id, std::vector<Id>>::unordered_map; // Inherit constructors

/// @brief Explode all possible paths from sourceId to targetId
/// @param sourceId The starting point of the paths
/// @param targetId The end point of the paths
/// @return A list of vectors, each vector representing a path from sourceId to targetId
std::list<std::vector<Id>> explode(Id const sourceId, Id const targetId) const;
};
} // namespace dsf::mobility
Loading
Loading