@@ -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