From 3a5ba7daf8759ce0a893bab994304e5f125972cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Uhl=C3=ADk?= <jan@uhlik.me>
Date: Thu, 29 Mar 2018 21:04:15 +0200
Subject: [PATCH] Add Jarkni-Prim algorithm.

---
 .../src/spanning_tree/JarnikPrim.cpp          |  22 ++++
 .../src/spanning_tree/JarnikPrim.hpp          | 110 ++++++++++++++++++
 2 files changed, 132 insertions(+)
 create mode 100644 alib2graph_algo/src/spanning_tree/JarnikPrim.cpp
 create mode 100644 alib2graph_algo/src/spanning_tree/JarnikPrim.hpp

diff --git a/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp b/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp
new file mode 100644
index 0000000000..db6d6ea828
--- /dev/null
+++ b/alib2graph_algo/src/spanning_tree/JarnikPrim.cpp
@@ -0,0 +1,22 @@
+// JarnikPrim.cpp
+//
+//     Created on: 19. 03. 2018
+//         Author: Jan Uhlik
+//    Modified by:
+//
+// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
+// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
+
+#include "JarnikPrim.hpp"
+
+#include <registration/AlgoRegistration.hpp>
+namespace {
+
+// ---------------------------------------------------------------------------------------------------------------------
+// uni-directional
+
+auto JarnikPrim1 = registration::AbstractRegister<spanning_tree::JarnikPrim,
+                                                  graph::WeightedUndirectedGraph<>,
+                                                  const graph::WeightedUndirectedGraph<> &,
+                                                  const DefaultNodeType &>(spanning_tree::JarnikPrim::findSpanningTree);
+}
diff --git a/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp b/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp
new file mode 100644
index 0000000000..c2900eb003
--- /dev/null
+++ b/alib2graph_algo/src/spanning_tree/JarnikPrim.hpp
@@ -0,0 +1,110 @@
+// JarnikPrim.hpp
+//
+//     Created on: 19. 03. 2018
+//         Author: Jan Uhlik
+//    Modified by:
+//
+// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
+// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
+
+#ifndef ALIB2_JARNIKPRIM_HPP
+#define ALIB2_JARNIKPRIM_HPP
+
+#include <alib/pair>
+#include <alib/set>
+#include <alib/map>
+
+#include <common/SupportFunction.hpp>
+
+namespace spanning_tree {
+
+class JarnikPrim {
+// ---------------------------------------------------------------------------------------------------------------------
+ public:
+
+  template<typename TGraph, typename TNode>
+  static
+  TGraph
+  findSpanningTree(const TGraph &graph, const TNode &start);
+
+// =====================================================================================================================
+
+ private:
+
+  template<typename TNode, typename TWeight>
+  struct Data {
+    ext::set<ext::pair<TWeight, TNode>> queue; // priority queue
+    ext::map<TNode, TWeight> g; // distances (aka G score)
+    ext::map<TNode, TNode> p; // parents
+  };
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+  template<typename TNode, typename TWeight>
+  inline static void init(JarnikPrim::Data<TNode, TWeight> &data, const TNode &start);
+
+};
+
+// =====================================================================================================================
+
+template<typename TGraph, typename TNode>
+TGraph JarnikPrim::findSpanningTree(const TGraph &graph, const TNode &start) {
+  using weight_type = typename TGraph::edge_type::weight_type;
+
+  TGraph res;
+  Data<TNode, weight_type> data;
+
+  // Init search
+  init(data, start);
+
+  while (!data.queue.empty()) {
+    TNode n = data.queue.begin()->second;
+    data.queue.erase(data.queue.begin());
+
+    // If not already in spanning tree add it
+    auto search = data.p.find(n);
+    if (search != data.p.end()) {
+      res.addEdge(search->second, n, data.g.at(n));
+    }
+
+    for (const auto &s_edge: graph.successorEdges(n)) {
+      const TNode &s = common::SupportFunction::other(s_edge, n); // successor
+
+      // Calculate new G score
+      weight_type gscore = s_edge.weight();
+
+      // Search if the node s was already visited
+      auto search_d = data.g.find(s);
+
+      // If not or the distance can be improve do relaxation
+      if (search_d == data.g.end() || search_d->second > gscore) {
+        // Search if the node s is in OPEN
+        auto search_q = data.queue.find(ext::make_pair(search_d->second, s));
+        if (search_q != data.queue.end()) {
+          // Erase node from priority queue
+          data.queue.erase(search_q);
+        }
+
+        data.g[s] = gscore;
+        data.p.insert_or_assign(s, n);
+        data.queue.insert(ext::make_pair(data.g[s], s));
+      }
+    }
+  }
+
+  return res;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+template<typename TNode, typename TWeight>
+void JarnikPrim::init(JarnikPrim::Data<TNode, TWeight> &data, const TNode &start) {
+  data.g[start] = 0;
+  data.p.insert_or_assign(start, start);
+  data.queue.insert(ext::make_pair(data.g[start], start));
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+
+} // namespace spanning_tree
+#endif //ALIB2_JARNIKPRIM_HPP
-- 
GitLab