Skip to content

Commit

Permalink
Added documentation to PathSearch and visitors
Browse files Browse the repository at this point in the history
  • Loading branch information
JoBuRo committed Jun 23, 2024
1 parent 1aa8350 commit 536e5fe
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 9 deletions.
64 changes: 57 additions & 7 deletions src/engine/PathSearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,39 @@ using IdToNodeMap = std::unordered_map<

enum PathSearchAlgorithm { ALL_PATHS, SHORTEST_PATHS };

/**
* @brief Struct to hold configuration parameters for the path search.
*/
struct PathSearchConfiguration {
// The path search algorithm to use.
PathSearchAlgorithm algorithm_;
// The source node ID.
Id source_;
std::vector<Id> targets_;
Variable start_;
Variable end_;
Variable pathColumn_;
Variable edgeColumn_;
// A list of target node IDs.
std::vector<Id> targets_;
// Variable representing the start column in the result.
Variable start_;
// Variable representing the end column in the result.
Variable end_;
// Variable representing the path column in the result.
Variable pathColumn_;
// Variable representing the edge column in the result.
Variable edgeColumn_;
// Variables representing edge property columns.
std::vector<Variable> edgeProperties_;
};

/**
* @brief Class to perform various path search algorithms on a graph.
*/
class PathSearch : public Operation {
std::shared_ptr<QueryExecutionTree> subtree_;
size_t resultWidth_;
VariableToColumnMap variableColumns_;

// The graph on which the path search is performed.
Graph graph_;
// Configuration for the path search.
PathSearchConfiguration config_;
Id source_;
std::vector<Id> targets_;
Expand All @@ -57,8 +73,8 @@ class PathSearch : public Operation {
PathSearchConfiguration config);

std::vector<QueryExecutionTree*> getChildren() override;
const Id& getSource() const { return source_; }
const std::vector<Id>& getTargets() const { return targets_; }
const Id& getSource() const { return config_.source_; }
const std::vector<Id>& getTargets() const { return config_.targets_; }

const PathSearchConfiguration& getConfig() const { return config_; }

Expand All @@ -84,13 +100,47 @@ class PathSearch : public Operation {
VariableToColumnMap computeVariableToColumnMap() const override;

private:
/**
* @brief Builds the graph from the given nodes and edge properties.
* @param startNodes A span of start nodes.
* @param endNodes A span of end nodes.
* @param edgePropertyLists A span of edge property lists.
*/
void buildGraph(std::span<const Id> startNodes, std::span<const Id> endNodes,
std::span<std::span<const Id>> edgePropertyLists);

/**
* @brief Builds the mapping from node IDs to indices.
* @param startNodes A span of start nodes.
* @param endNodes A span of end nodes.
*/
void buildMapping(std::span<const Id> startNodes,
std::span<const Id> endNodes);

/**
* @brief Finds paths based on the configured algorithm.
* @return A vector of paths.
*/
std::vector<Path> findPaths() const;

/**
* @brief Finds all paths in the graph.
* @return A vector of all paths.
*/
std::vector<Path> allPaths() const;

/**
* @brief Finds the shortest paths in the graph.
* @return A vector of the shortest paths.
*/
std::vector<Path> shortestPaths() const;

/**
* @brief Converts paths to a result table with a specified width.
* @tparam WIDTH The width of the result table.
* @param tableDyn The dynamic table to store the results.
* @param paths The vector of paths to convert.
*/
template <size_t WIDTH>
void pathsToResultTable(IdTable& tableDyn, std::vector<Path>& paths) const;
};
124 changes: 122 additions & 2 deletions src/engine/PathSearchVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,66 +13,134 @@
#include <boost/graph/graph_selectors.hpp>
#include <boost/graph/graph_traits.hpp>


/**
* @brief Represents an edge in the graph.
*/
struct Edge {
// The starting node ID.
uint64_t start_;

// The ending node ID.
uint64_t end_;

// Properties associated with the edge.
std::vector<Id> edgeProperties_;

// The weight of the edge.
double weight_ = 1;

/**
* @brief Converts the edge to a pair of IDs.
* @return A pair of IDs representing the start and end of the edge.
*/
std::pair<Id, Id> toIds() const {
return {Id::fromBits(start_), Id::fromBits(end_)};
}
};

/**
* @brief Represents a path consisting of multiple edges.
*/
struct Path {
// The edges that make up the path.
std::vector<Edge> edges_;

/**
* @brief Checks if the path is empty.
* @return True if the path is empty, false otherwise.
*/
bool empty() const { return edges_.empty(); }

/**
* @brief Returns the number of edges in the path.
* @return The number of edges in the path.
*/
size_t size() const { return edges_.size(); }

/**
* @brief Adds an edge to the end of the path.
* @param edge The edge to add.
*/
void push_back(Edge edge) { edges_.push_back(edge); }

/**
* @brief Reverses the order of the edges in the path.
*/
void reverse() { std::reverse(edges_.begin(), edges_.end()); }

/**
* @brief Returns the ID of the first node in the path, if it exists.
* @return The ID of the first node, or std::nullopt if the path is empty.
*/
std::optional<uint64_t> firstNode() const {
return !empty() ? std::optional<uint64_t>{edges_.front().start_}
: std::nullopt;
}

/**
* @brief Returns the ID of the last node in the path, if it exists.
* @return The ID of the last node, or std::nullopt if the path is empty.
*/
std::optional<uint64_t> lastNode() const {
return !empty() ? std::optional<uint64_t>{edges_.back().end_}
: std::nullopt;
}

/**
* @brief Checks if the path ends with the given node ID.
* @param node The node ID to check.
* @return True if the path ends with the given node ID, false otherwise.
*/
bool ends_with(uint64_t node) const {
return (!empty() && node == lastNode().value());
}
};


/**
* @brief Boost graph types and descriptors.
*/
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
boost::no_property, Edge>
Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
typedef boost::graph_traits<Graph>::edge_descriptor EdgeDescriptor;

/**
* @brief Visitor for performing a depth-first search to find all paths.
*/
class AllPathsVisitor : public boost::default_dfs_visitor {
// Set of target node IDs.
std::unordered_set<uint64_t> targets_;

// Reference to the current path being explored.
Path& currentPath_;

// Reference to the collection of all found paths.
std::vector<Path>& allPaths_;

// Mapping from indices to IDs.
const std::vector<Id>& indexToId_;

public:
/**
* @brief Constructor for AllPathsVisitor.
* @param targets Set of target node IDs.
* @param path Reference to the current path being explored.
* @param paths Reference to the collection of all found paths.
* @param indexToId Mapping from indices to IDs.
*/
AllPathsVisitor(std::unordered_set<uint64_t> targets, Path& path,
std::vector<Path>& paths, const std::vector<Id>& indexToId)
: targets_(std::move(targets)),
currentPath_(path),
allPaths_(paths),
indexToId_(indexToId) {}

/**
* @brief Examines an edge during the depth-first search.
* @param edgeDesc The descriptor of the edge being examined.
* @param graph The graph being searched.
*/
void examine_edge(EdgeDescriptor edgeDesc, const Graph& graph) {
const Edge& edge = graph[edgeDesc];
if (targets_.empty() || (currentPath_.ends_with(edge.start_) && targets_.find(edge.end_) != targets_.end())) {
Expand All @@ -82,11 +150,21 @@ class AllPathsVisitor : public boost::default_dfs_visitor {
}
}

/**
* @brief Processes a tree edge during the depth-first search.
* @param edgeDesc The descriptor of the edge being processed.
* @param graph The graph being searched.
*/
void tree_edge(EdgeDescriptor edgeDesc, const Graph& graph) {
const Edge& edge = graph[edgeDesc];
currentPath_.edges_.push_back(edge);
}

/**
* @brief Called when a vertex has been finished during the depth-first search.
* @param vertex The descriptor of the vertex being finished.
* @param graph The graph being searched.
*/
void finish_vertex(VertexDescriptor vertex, const Graph& graph) {
(void)graph;
if (!currentPath_.empty() && Id::fromBits(currentPath_.lastNode().value()) == indexToId_[vertex]) {
Expand All @@ -95,15 +173,38 @@ class AllPathsVisitor : public boost::default_dfs_visitor {
}
};

/**
* @brief Visitor for performing Dijkstra's algorithm to find all shortest paths.
*/
class DijkstraAllPathsVisitor : public boost::default_dijkstra_visitor {
// The source vertex descriptor.
VertexDescriptor source_;

// Set of target node IDs.
std::unordered_set<uint64_t> targets_;

// Reference to the current path being explored.
Path& currentPath_;

// Reference to the collection of all found paths.
std::vector<Path>& allPaths_;

// Reference to the vector of predecessors.
std::vector<VertexDescriptor>& predecessors_;

// Reference to the vector of distances.
std::vector<double>& distances_;

public:
/**
* @brief Constructor for DijkstraAllPathsVisitor.
* @param source The source vertex descriptor.
* @param targets Set of target node IDs.
* @param path Reference to the current path being explored.
* @param paths Reference to the collection of all found paths.
* @param predecessors Reference to the vector of predecessors.
* @param distances Reference to the vector of distances.
*/
DijkstraAllPathsVisitor(VertexDescriptor source,
std::unordered_set<uint64_t> targets, Path& path,
std::vector<Path>& paths,
Expand All @@ -116,18 +217,37 @@ class DijkstraAllPathsVisitor : public boost::default_dijkstra_visitor {
predecessors_(predecessors),
distances_(distances) {}

/**
* @brief Returns the vector of predecessors.
* @return The vector of predecessors.
*/
const std::vector<VertexDescriptor>& getPredecessors() const {
return predecessors_;
}

/**
* @brief Returns the vector of distances.
* @return The vector of distances.
*/
const std::vector<double>& getDistances() const { return distances_; }

/**
* @brief Called when an edge is relaxed during Dijkstra's algorithm.
* @param edgeDesc The descriptor of the edge being relaxed.
* @param graph The graph being searched.
*/
void edge_relaxed(EdgeDescriptor edgeDesc, const Graph& graph) {
const Edge& edge = graph[edgeDesc];
if (targets_.empty() || targets_.find(edge.end_) != targets_.end()) {
rebuild_path(target(edgeDesc, graph), graph);
}
}

/**
* @brief Rebuilds the path from the source to the given vertex.
* @param vertex The descriptor of the vertex.
* @param graph The graph being searched.
*/
void rebuild_path(VertexDescriptor vertex, const Graph& graph) {
currentPath_.edges_.clear();
for (VertexDescriptor v = vertex; v != source_; v = predecessors_[v]) {
Expand Down

0 comments on commit 536e5fe

Please sign in to comment.