@@ -456,5 +456,153 @@ const DijkstraResult Graph<T>::dijkstra_deterministic2(
456456 return result;
457457}
458458
459+ template <typename T>
460+ const DijkstraResult Graph<T>::criticalpath_deterministic(
461+ const Node<T>& source, const Node<T>& target) const {
462+ DijkstraResult result;
463+ auto nodeSet = Graph<T>::getNodeSet ();
464+
465+ auto source_node_it = std::find_if (
466+ nodeSet.begin (), nodeSet.end (),
467+ [&source](auto node) { return node->getUserId () == source.getUserId (); });
468+ if (source_node_it == nodeSet.end ()) {
469+ // check if source node exist in the graph
470+ result.errorMessage = ERR_SOURCE_NODE_NOT_IN_GRAPH;
471+ return result;
472+ }
473+
474+ auto target_node_it = std::find_if (
475+ nodeSet.begin (), nodeSet.end (),
476+ [&target](auto node) { return node->getUserId () == target.getUserId (); });
477+ if (target_node_it == nodeSet.end ()) {
478+ // check if target node exist in the graph
479+ result.errorMessage = ERR_TARGET_NODE_NOT_IN_GRAPH;
480+ return result;
481+ }
482+ // n denotes the number of vertices in graph
483+ // unused
484+ // auto n = cachedAdjMatrix->size();
485+
486+ // setting all the distances initially to -INF_DOUBLE
487+ std::unordered_map<shared<const Node<T>>, double , nodeHash<T>> dist;
488+ std::map<std::string, shared<const Node<T>>> userIds;
489+
490+ for (const auto & node : nodeSet) {
491+ dist[node] = -INF_DOUBLE;
492+ userIds[node->getUserId ()] = node;
493+ }
494+
495+ std::unordered_map<shared<const Node<T>>, size_t , nodeHash<T>> stableIds;
496+ size_t index (0 );
497+ for (const auto & it : userIds) stableIds[it.second ] = index++;
498+
499+ // creating a max heap using priority queue
500+ // first element of pair contains the distance
501+ // second element of pair contains the vertex
502+
503+ struct VertexInfo {
504+ double distance = 0 ;
505+ size_t sumOfIds = 0 ;
506+ shared<const Node<T>> node;
507+ };
508+
509+ struct VertexInfoLesser {
510+ bool operator ()(const VertexInfo& a, const VertexInfo& b) const {
511+ if (a.distance == b.distance ) return a.sumOfIds < b.sumOfIds ;
512+ return a.distance < b.distance ;
513+ };
514+ };
515+
516+ std::priority_queue<VertexInfo, std::vector<VertexInfo>, VertexInfoLesser>
517+ pq;
518+
519+ // pushing the source vertex 's' with 0 distance in min heap
520+ pq.push (VertexInfo{0.0 , stableIds[*source_node_it], *source_node_it});
521+
522+ // marking the distance of source as 0
523+ dist[*source_node_it] = 0 ;
524+
525+ std::unordered_map<std::string, std::string> parent;
526+ parent[source.getUserId ()] = " " ;
527+
528+ while (!pq.empty ()) {
529+ // second element of pair denotes the node / vertex
530+ shared<const Node<T>> currentNode = pq.top ().node ;
531+ // first element of pair denotes the distance
532+ double currentDist = pq.top ().distance ;
533+ auto currentNodesSum = pq.top ().sumOfIds ;
534+
535+ pq.pop ();
536+
537+ // for all the reachable vertex from the currently exploring vertex
538+ // we will try to minimize the distance
539+ if (cachedAdjMatrix->find (currentNode) != cachedAdjMatrix->end ()) {
540+ for (const auto & elem : cachedAdjMatrix->at (currentNode)) {
541+ // minimizing distances
542+ if (elem.second ->isWeighted ().has_value () &&
543+ elem.second ->isWeighted ().value ()) {
544+ if (elem.second ->isDirected ().has_value () &&
545+ elem.second ->isDirected ().value ()) {
546+ shared<const DirectedWeightedEdge<T>> dw_edge =
547+ std::static_pointer_cast<const DirectedWeightedEdge<T>>(
548+ elem.second );
549+ if (dw_edge->getWeight () < 0 ) {
550+ result.errorMessage = ERR_NEGATIVE_WEIGHTED_EDGE;
551+ return result;
552+ } else if (currentDist + dw_edge->getWeight () > dist[elem.first ]) {
553+ dist[elem.first ] = currentDist + dw_edge->getWeight ();
554+ pq.push (VertexInfo{dist[elem.first ],
555+ currentNodesSum + stableIds[elem.first ],
556+ elem.first });
557+ parent[elem.first .get ()->getUserId ()] =
558+ currentNode.get ()->getUserId ();
559+ }
560+ } else if (elem.second ->isDirected ().has_value () &&
561+ !elem.second ->isDirected ().value ()) {
562+ shared<const UndirectedWeightedEdge<T>> udw_edge =
563+ std::static_pointer_cast<const UndirectedWeightedEdge<T>>(
564+ elem.second );
565+ if (udw_edge->getWeight () < 0 ) {
566+ result.errorMessage = ERR_NEGATIVE_WEIGHTED_EDGE;
567+ return result;
568+ } else if (currentDist + udw_edge->getWeight () > dist[elem.first ]) {
569+ dist[elem.first ] = currentDist + udw_edge->getWeight ();
570+ pq.push (VertexInfo{dist[elem.first ],
571+ currentNodesSum + stableIds[elem.first ],
572+ elem.first });
573+ parent[elem.first .get ()->getUserId ()] =
574+ currentNode.get ()->getUserId ();
575+ }
576+ } else {
577+ // ERROR it shouldn't never returned ( does not exist a Node
578+ // Weighted and not Directed/Undirected)
579+ result.errorMessage = ERR_NO_DIR_OR_UNDIR_EDGE;
580+ return result;
581+ }
582+ } else {
583+ // No Weighted Edge
584+ result.errorMessage = ERR_NO_WEIGHTED_EDGE;
585+ return result;
586+ }
587+ }
588+ }
589+ }
590+ if (dist[*target_node_it] != INF_DOUBLE) {
591+ result.success = true ;
592+ result.errorMessage = " " ;
593+ result.result = dist[*target_node_it];
594+ std::string id = target.getUserId ();
595+ while (parent[id] != " " ) {
596+ result.path .push_back (id);
597+ id = parent[id];
598+ }
599+ result.path .push_back (source.getUserId ());
600+ std::reverse (result.path .begin (), result.path .end ());
601+ return result;
602+ }
603+ result.errorMessage = ERR_TARGET_NODE_NOT_REACHABLE;
604+ return result;
605+ }
606+
459607} // namespace CXXGraph
460608#endif // __CXXGRAPH_DIJKSTRA_IMPL_H__
0 commit comments