Skip to content

Commit 8f1d51c

Browse files
committed
#582: add Dijkstra based Critical Path compute algorithm
1 parent c1d7600 commit 8f1d51c

2 files changed

Lines changed: 151 additions & 4 deletions

File tree

examples/DijkstraExample/dijkstra_example.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ int main() {
1010
CXXGraph::Node<int> node2("2", 2);
1111
CXXGraph::Node<int> node3("3", 3);
1212

13-
CXXGraph::DirectedWeightedEdge<int> edge1("1", node1, node2, 2.0);
14-
CXXGraph::DirectedWeightedEdge<int> edge2("2", node2, node3, 2.0);
15-
CXXGraph::DirectedWeightedEdge<int> edge3("3", node0, node1, 2.0);
16-
CXXGraph::DirectedWeightedEdge<int> edge4("4", node0, node3, 1.0);
13+
CXXGraph::DirectedWeightedEdge<int> edge1(1, node1, node2, 2.0);
14+
CXXGraph::DirectedWeightedEdge<int> edge2(2, node2, node3, 2.0);
15+
CXXGraph::DirectedWeightedEdge<int> edge3(3, node0, node1, 2.0);
16+
CXXGraph::DirectedWeightedEdge<int> edge4(4, node0, node3, 1.0);
1717

1818
CXXGraph::T_EdgeSet<int> edgeSet;
1919
edgeSet.insert(make_shared<CXXGraph::DirectedWeightedEdge<int>>(edge1));

include/CXXGraph/Graph/Algorithm/Dijkstra_impl.hpp

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,5 +598,152 @@ const DijkstraResult Graph<T>::criticalpath_deterministic(
598598
return result;
599599
}
600600

601+
template <typename T>
602+
const DijkstraResult Graph<T>::criticalpath_deterministic(
603+
const Node<T>& source, const Node<T>& target) const {
604+
DijkstraResult result;
605+
auto nodeSet = Graph<T>::getNodeSet();
606+
607+
auto source_node_it = std::find_if(
608+
nodeSet.begin(), nodeSet.end(),
609+
[&source](auto node) { return node->getUserId() == source.getUserId(); });
610+
if (source_node_it == nodeSet.end()) {
611+
// check if source node exist in the graph
612+
result.errorMessage = ERR_SOURCE_NODE_NOT_IN_GRAPH;
613+
return result;
614+
}
615+
616+
auto target_node_it = std::find_if(
617+
nodeSet.begin(), nodeSet.end(),
618+
[&target](auto node) { return node->getUserId() == target.getUserId(); });
619+
if (target_node_it == nodeSet.end()) {
620+
// check if target node exist in the graph
621+
result.errorMessage = ERR_TARGET_NODE_NOT_IN_GRAPH;
622+
return result;
623+
}
624+
// n denotes the number of vertices in graph
625+
// unused
626+
// auto n = cachedAdjMatrix->size();
627+
628+
// setting all the distances initially to -INF_DOUBLE
629+
std::unordered_map<shared<const Node<T>>, double, nodeHash<T>> dist;
630+
std::map<std::string, shared<const Node<T>>> userIds;
631+
632+
for (const auto& node : nodeSet) {
633+
dist[node] = -INF_DOUBLE;
634+
userIds[node->getUserId()] = node;
635+
}
636+
637+
std::unordered_map<shared<const Node<T>>, size_t, nodeHash<T>> stableIds;
638+
size_t index(0);
639+
for (const auto& it : userIds) stableIds[it.second] = index++;
640+
641+
// creating a max heap using priority queue
642+
// first element of pair contains the distance
643+
// second element of pair contains the vertex
644+
645+
struct VertexInfo {
646+
double distance = 0;
647+
size_t sumOfIds = 0;
648+
shared<const Node<T>> node;
649+
};
650+
651+
struct VertexInfoLesser {
652+
bool operator()(const VertexInfo& a, const VertexInfo& b) const {
653+
if (a.distance == b.distance) return a.sumOfIds < b.sumOfIds;
654+
return a.distance < b.distance;
655+
};
656+
};
657+
658+
std::priority_queue<VertexInfo, std::vector<VertexInfo>, VertexInfoLesser> pq;
659+
660+
// pushing the source vertex 's' with 0 distance in min heap
661+
pq.push(VertexInfo{0.0, stableIds[*source_node_it], *source_node_it});
662+
663+
// marking the distance of source as 0
664+
dist[*source_node_it] = 0;
665+
666+
std::unordered_map<std::string, std::string> parent;
667+
parent[source.getUserId()] = "";
668+
669+
while (!pq.empty()) {
670+
// second element of pair denotes the node / vertex
671+
shared<const Node<T>> currentNode = pq.top().node;
672+
// first element of pair denotes the distance
673+
double currentDist = pq.top().distance;
674+
auto currentNodesSum = pq.top().sumOfIds;
675+
676+
pq.pop();
677+
678+
// for all the reachable vertex from the currently exploring vertex
679+
// we will try to minimize the distance
680+
if (cachedAdjMatrix->find(currentNode) != cachedAdjMatrix->end()) {
681+
for (const auto& elem : cachedAdjMatrix->at(currentNode)) {
682+
// minimizing distances
683+
if (elem.second->isWeighted().has_value() &&
684+
elem.second->isWeighted().value()) {
685+
if (elem.second->isDirected().has_value() &&
686+
elem.second->isDirected().value()) {
687+
shared<const DirectedWeightedEdge<T>> dw_edge =
688+
std::static_pointer_cast<const DirectedWeightedEdge<T>>(
689+
elem.second);
690+
if (dw_edge->getWeight() < 0) {
691+
result.errorMessage = ERR_NEGATIVE_WEIGHTED_EDGE;
692+
return result;
693+
} else if (currentDist + dw_edge->getWeight() > dist[elem.first]) {
694+
dist[elem.first] = currentDist + dw_edge->getWeight();
695+
pq.push(VertexInfo{dist[elem.first],
696+
currentNodesSum + stableIds[elem.first],
697+
elem.first});
698+
parent[elem.first.get()->getUserId()] =
699+
currentNode.get()->getUserId();
700+
}
701+
} else if (elem.second->isDirected().has_value() &&
702+
!elem.second->isDirected().value()) {
703+
shared<const UndirectedWeightedEdge<T>> udw_edge =
704+
std::static_pointer_cast<const UndirectedWeightedEdge<T>>(
705+
elem.second);
706+
if (udw_edge->getWeight() < 0) {
707+
result.errorMessage = ERR_NEGATIVE_WEIGHTED_EDGE;
708+
return result;
709+
} else if (currentDist + udw_edge->getWeight() > dist[elem.first]) {
710+
dist[elem.first] = currentDist + udw_edge->getWeight();
711+
pq.push(VertexInfo{dist[elem.first],
712+
currentNodesSum + stableIds[elem.first],
713+
elem.first});
714+
parent[elem.first.get()->getUserId()] =
715+
currentNode.get()->getUserId();
716+
}
717+
} else {
718+
// ERROR it shouldn't never returned ( does not exist a Node
719+
// Weighted and not Directed/Undirected)
720+
result.errorMessage = ERR_NO_DIR_OR_UNDIR_EDGE;
721+
return result;
722+
}
723+
} else {
724+
// No Weighted Edge
725+
result.errorMessage = ERR_NO_WEIGHTED_EDGE;
726+
return result;
727+
}
728+
}
729+
}
730+
}
731+
if (dist[*target_node_it] != INF_DOUBLE) {
732+
result.success = true;
733+
result.errorMessage = "";
734+
result.result = dist[*target_node_it];
735+
std::string id = target.getUserId();
736+
while (parent[id] != "") {
737+
result.path.push_back(id);
738+
id = parent[id];
739+
}
740+
result.path.push_back(source.getUserId());
741+
std::reverse(result.path.begin(), result.path.end());
742+
return result;
743+
}
744+
result.errorMessage = ERR_TARGET_NODE_NOT_REACHABLE;
745+
return result;
746+
}
747+
601748
} // namespace CXXGraph
602749
#endif // __CXXGRAPH_DIJKSTRA_IMPL_H__

0 commit comments

Comments
 (0)