diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a6fd5671afe41e195fb074c0ec31046445c01f4..aa173322eca5f46bf10e4c90da678660977aa48c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.1.3)
 # Project settings
 # ============================================================================
 project(hglib
-        VERSION 1.2.1)
+        VERSION 1.3.0)
 
 
 # ============================================================================
diff --git a/include/hglib/hypergraph/Hypergraph.h b/include/hglib/hypergraph/Hypergraph.h
index c25ddd87c8b62216a07d36b3f5a15a5a0ccdb5ea..63f29d3753ec51a1d29c02c4ae26921f1d4931d4 100644
--- a/include/hglib/hypergraph/Hypergraph.h
+++ b/include/hglib/hypergraph/Hypergraph.h
@@ -58,6 +58,10 @@ template <template <typename> typename VertexTemplate_t,
           typename HypergraphProperty = emptyProperty>
 class Hypergraph : virtual public HypergraphInterface<VertexTemplate_t,
         Hyperedge_t, VertexProperty, EdgeProperty, HypergraphProperty> {
+  // Declare any instantiation of this template class as friend
+  template <template <typename> class, typename, typename, typename, typename>
+  friend class Hypergraph;
+
  public:
   /// Alias for the vertex type
   using Vertex_t = typename HypergraphInterface<VertexTemplate_t, Hyperedge_t,
@@ -97,6 +101,13 @@ class Hypergraph : virtual public HypergraphInterface<VertexTemplate_t,
   explicit Hypergraph(bool allowMultiHyperedges = true);
   /// Hypergraph copy constructor
   explicit Hypergraph(const Hypergraph& rhs);
+  /// Conversion constructor
+  template <typename OtherVP, typename OtherEP, typename OtherGP>
+  explicit Hypergraph(const Hypergraph<VertexTemplate_t,
+                                       Hyperedge_t,
+                                       OtherVP,
+                                       OtherEP,
+                                       OtherGP>& other);
 
   /// Hypergraph destructor
   virtual ~Hypergraph();
diff --git a/include/hglib/hypergraph/Hypergraph.hpp b/include/hglib/hypergraph/Hypergraph.hpp
index 4f9abbdc9ff590fa982ccaa9e403e050f20399b2..e38c56c24d5cdd34db91798d2da57aeb5f8b63b2 100644
--- a/include/hglib/hypergraph/Hypergraph.hpp
+++ b/include/hglib/hypergraph/Hypergraph.hpp
@@ -137,6 +137,72 @@ Hypergraph(const Hypergraph& other) :
   }
 }
 
+/**
+ * \brief Conversion constructor
+ *
+ * \details
+ * Allows to convert a graph to another graph with the same Vertex and Edge
+ * types but another set of (Vertex-, Edge- and Graph-) Properties
+ *
+ * \param other Hypergraph to be copied
+ */
+template <template <typename> typename VertexTemplate_t,
+          typename Hyperedge_t,
+          typename VertexProperty,
+          typename EdgeProperty,
+          typename GraphProperty>
+template <typename OtherVP, typename OtherEP, typename OtherGP>
+Hypergraph<VertexTemplate_t,
+           Hyperedge_t,
+           VertexProperty,
+           EdgeProperty,
+           GraphProperty>::
+Hypergraph(const Hypergraph<VertexTemplate_t,
+                            Hyperedge_t,
+                            OtherVP,
+                            OtherEP,
+                            OtherGP>& other) :
+    vertexMaxId_(-1),
+    allowMultiHyperedges_(other.allowMultiHyperedges_) {
+  try {
+    // create vertices_
+    vertices_ = create_filtered_vector<Vertex_t*>(
+        create_filtered_vector<Vertex_t*>(),
+        std::make_unique<NullptrFilter<Vertex_t*>>());
+    // create vertexProperties_
+    vertexProperties_ = create_filtered_vector<VertexProperty*>(
+        create_filtered_vector<VertexProperty*>(),
+        std::make_unique<NullptrFilter<VertexProperty*>>());
+
+    // copy vertices and initialize associated vertex properties
+    for (std::size_t i = 0; i < other.vertices_->size(); ++i) {
+      Vertex_t* vertex = other.vertices_->operator[](i);
+      ++vertexMaxId_;
+      // if vertex was deleted in directedHypergraph
+      if (vertex == nullptr) {
+        vertices_->push_back(nullptr);
+        vertexProperties_->push_back(nullptr);
+      } else {
+        // Copy vertex
+        vertices_->push_back(new Vertex_t(*vertex));
+        // Init vertex property
+        vertexProperties_->push_back(new VertexProperty());
+      }
+    }
+    // Init graph properties
+    hypergraphProperty_ = new GraphProperty();
+  } catch (std::bad_alloc &e) {
+    for (auto& vertex : *(vertices_.get())) {
+      delete vertex;
+    }
+    for (auto& vertexProperty : *(vertexProperties_.get())) {
+      delete vertexProperty;
+    }
+    delete hypergraphProperty_;
+    throw;
+  }
+}
+
 
 /**
  * \brief Hypergraph destructor
diff --git a/include/hglib/hypergraph/directed/DirectedHypergraph.h b/include/hglib/hypergraph/directed/DirectedHypergraph.h
index 6c5a03496db109c1da8d92e606b9e4613e2796bd..88c1c4cf9b812987e4728b49de2d3c0025f269e2 100644
--- a/include/hglib/hypergraph/directed/DirectedHypergraph.h
+++ b/include/hglib/hypergraph/directed/DirectedHypergraph.h
@@ -127,6 +127,10 @@ class DirectedHypergraph : public DirectedHypergraphInterface<
           "derived from DirectedHyperedgeBase, e.g. use as second template "
           "parameter DirectedHyperedge or NamedDirectedHyperedge");
 
+  // Declare any instantiation of this template class as friend
+  template <template <typename> class, typename, typename, typename, typename>
+  friend class DirectedHypergraph;
+
 
  public:
   /// Alias for the directed vertex type
@@ -189,6 +193,14 @@ class DirectedHypergraph : public DirectedHypergraphInterface<
   /// Copy constructor
   explicit DirectedHypergraph(
           const DirectedHypergraph& directedHypergraph);
+  /// Conversion constructor
+  template <typename OtherVP, typename OtherEP, typename OtherGP>
+  explicit DirectedHypergraph(
+      const DirectedHypergraph<VertexTemplate_t,
+                               Hyperarc_t,
+                               OtherVP,
+                               OtherEP,
+                               OtherGP>& other);
   /// DirectedHypergraph destructor
   virtual ~DirectedHypergraph();
 
diff --git a/include/hglib/hypergraph/directed/DirectedHypergraph.hpp b/include/hglib/hypergraph/directed/DirectedHypergraph.hpp
index 2970228bc68533cf646f0d7088529aadd14d6bd9..b31c13e515441f62ce890c8e1436b4d72c4d0bd8 100644
--- a/include/hglib/hypergraph/directed/DirectedHypergraph.hpp
+++ b/include/hglib/hypergraph/directed/DirectedHypergraph.hpp
@@ -142,6 +142,92 @@ DirectedHypergraph(const DirectedHypergraph& other) :
   }
 }
 
+/**
+ * \brief Conversion constructor
+ *
+ * \details
+ * Allows to convert a graph to another graph with the same Vertex and Edge
+ * types but another set of (Vertex-, Edge- and Graph-) Properties
+ *
+ * \param other Hypergraph to be copied
+ */
+template <template <typename> typename VertexTemplate_t,
+          typename Hyperarc_t,
+          typename VertexProperty,
+          typename HyperarcProperty,
+          typename HypergraphProperty>
+template <typename OtherVP, typename OtherEP, typename OtherGP>
+DirectedHypergraph<
+    VertexTemplate_t,
+    Hyperarc_t,
+    VertexProperty,
+    HyperarcProperty,
+    HypergraphProperty>::
+DirectedHypergraph(const DirectedHypergraph<VertexTemplate_t,
+                                            Hyperarc_t,
+                                            OtherVP,
+                                            OtherEP,
+                                            OtherGP>& other) :
+    DirectedHypergraphInterface<VertexTemplate_t,
+                                Hyperarc_t,
+                                VertexProperty,
+                                HyperarcProperty,
+                                HypergraphProperty>(),
+    Hypergraph<VertexTemplate_t,
+               Hyperarc_t,
+               VertexProperty,
+               HyperarcProperty,
+               HypergraphProperty>(other),
+    hyperarcMaxId_(-1) {
+  try {
+    // Initialise (empty) hyperarcs_
+    hyperarcs_ = create_filtered_vector<Hyperarc_t*>(
+        create_filtered_vector<Hyperarc_t*>(),
+        std::make_unique<NullptrFilter<Hyperarc_t*>>());
+    // Initialise (empty) hyperarcProperties_
+    hyperarcProperties_ =
+        create_filtered_vector<HyperarcProperty_type*>(
+            create_filtered_vector<HyperarcProperty_type*>(),
+            std::make_unique<NullptrFilter<HyperarcProperty_type*>>());
+    // Copy hyperarcs and init associated properties
+    for (std::size_t i = 0; i < other.hyperarcs_->size(); ++i) {
+      Hyperarc_t* hyperarc = other.hyperarcs_->operator[](i);
+      ++hyperarcMaxId_;
+      // if hyperarc was deleted in other
+      if (hyperarc == nullptr) {
+        hyperarcs_->push_back(nullptr);
+        hyperarcProperties_->push_back(nullptr);
+      } else {
+        Hyperarc_t* copy = new Hyperarc_t(*hyperarc);
+        // Add tails to hyperarc
+        for (const auto& vertex : *(hyperarc->tails_.get())) {
+          auto& tail = this->vertices_->operator[](vertex->id());
+          copy->addTailVertex(tail);
+          tail->addOutHyperarc(copy);
+        }
+        // Add heads to hyperarc
+        for (const auto& vertex : *(hyperarc->heads_.get())) {
+          auto& head = this->vertices_->operator[](vertex->id());
+          copy->addHeadVertex(head);
+          head->addInHyperarc(copy);
+        }
+        // Add hyperarc to hypergraph
+        hyperarcs_->push_back(copy);
+        // Init hyperarc property
+        hyperarcProperties_->push_back(new HyperarcProperty());
+      }
+    }
+  } catch (std::bad_alloc& e) {
+    for (auto& hyperarc : *(hyperarcs_.get())) {
+      delete hyperarc;
+    }
+    for (auto& hyperarcProperty : *(hyperarcProperties_.get())) {
+      delete hyperarcProperty;
+    }
+    throw;
+  }
+}
+
 /**
  * \brief DirectedHypergraph destructor
  *
diff --git a/include/hglib/hypergraph/undirected/UndirectedHypergraph.h b/include/hglib/hypergraph/undirected/UndirectedHypergraph.h
index 08fd7fb8719cdd597711049c9052ce59f1aab949..7b2f2cb03e53eac16009c2b6299a1bea2912393a 100644
--- a/include/hglib/hypergraph/undirected/UndirectedHypergraph.h
+++ b/include/hglib/hypergraph/undirected/UndirectedHypergraph.h
@@ -125,6 +125,10 @@ class UndirectedHypergraph : public UndirectedHypergraphInterface<
           "from HyperedgeBase, e.g. use as second template parameter "
           "UndirectedHyperedge or NamedUndirectedHyperedge");
 
+  // Declare any instantiation of this template class as friend
+  template <template <typename> class, typename, typename, typename, typename>
+  friend class UndirectedHypergraph;
+
  public:
   /// Alias for the directed vertex type
   using Vertex_t = typename UndirectedHypergraphInterface<VertexTemplate_t,
@@ -192,6 +196,14 @@ class UndirectedHypergraph : public UndirectedHypergraphInterface<
   /// UndirectedHypergraph copy constructor
   explicit UndirectedHypergraph(
           const UndirectedHypergraph& undirectedHypergraph);
+  /// Conversion constructor
+  template <typename OtherVP, typename OtherEP, typename OtherGP>
+  explicit UndirectedHypergraph(
+      const UndirectedHypergraph<VertexTemplate_t,
+                                 Hyperedge_t,
+                                 OtherVP,
+                                 OtherEP,
+                                 OtherGP>& other);
   /// Copy assignment operator
   UndirectedHypergraph& operator=(
           const UndirectedHypergraph& source);
diff --git a/include/hglib/hypergraph/undirected/UndirectedHypergraph.hpp b/include/hglib/hypergraph/undirected/UndirectedHypergraph.hpp
index be68d1ca05ec16ce2e884e49ecfafb107e88b281..0622defd19fd29e604af39e9bea1423a238bb1f9 100644
--- a/include/hglib/hypergraph/undirected/UndirectedHypergraph.hpp
+++ b/include/hglib/hypergraph/undirected/UndirectedHypergraph.hpp
@@ -131,6 +131,84 @@ UndirectedHypergraph(
   }
 }
 
+/**
+ * \brief Conversion constructor
+ *
+ * \details
+ * Allows to convert a graph to another graph with the same Vertex and Edge
+ * types but another set of (Vertex-, Edge- and Graph-) Properties
+ *
+ * \param other Hypergraph to be copied
+ */
+template <template <typename> typename VertexTemplate_t,
+          typename Hyperedge_t,
+          typename VertexProperty,
+          typename HyperedgeProperty,
+          typename HypergraphProperty>
+template <typename OtherVP, typename OtherEP, typename OtherGP>
+UndirectedHypergraph<VertexTemplate_t,
+                     Hyperedge_t,
+                     VertexProperty,
+                     HyperedgeProperty,
+                     HypergraphProperty>::
+UndirectedHypergraph(const UndirectedHypergraph<VertexTemplate_t,
+                                                Hyperedge_t,
+                                                OtherVP,
+                                                OtherEP,
+                                                OtherGP>& other) :
+    UndirectedHypergraphInterface<VertexTemplate_t,
+                                  Hyperedge_t,
+                                  VertexProperty,
+                                  HyperedgeProperty,
+                                  HypergraphProperty>(),
+    Hypergraph<VertexTemplate_t,
+               Hyperedge_t,
+               VertexProperty,
+               HyperedgeProperty,
+               HypergraphProperty>(other),
+    hyperedgeMaxId_(-1) {
+  try {
+    // Initialise (empty) hyperedges_
+    hyperedges_ = create_filtered_vector<Hyperedge_t*>(
+        create_filtered_vector<Hyperedge_t*>(),
+        std::make_unique<NullptrFilter<Hyperedge_t*>>());
+    // Initialise (empty)  hyperedgeProperties_
+    hyperedgeProperties_ = create_filtered_vector<HyperedgeProperty*>(
+        create_filtered_vector<HyperedgeProperty*>(),
+        std::make_unique<NullptrFilter<HyperedgeProperty*>>());
+    // Copy edges and init associated edge properties
+    for (std::size_t i = 0; i < other.hyperedges_->size(); ++i) {
+      Hyperedge_t* hyperedge = other.hyperedges_->operator[](i);
+      ++hyperedgeMaxId_;
+      // if hyperedge was deleted in other
+      if (hyperedge == nullptr) {
+        hyperedges_->push_back(nullptr);
+        hyperedgeProperties_->push_back(nullptr);
+      } else {
+        Hyperedge_t* copy = new Hyperedge_t(*hyperedge);
+        // Add vertices to hyperedge
+        for (const auto& vertex : *(hyperedge->vertices_.get())) {
+          auto& v = this->vertices_->operator[](vertex->id());
+          copy->addVertex(v);
+          v->addHyperedge(copy);
+        }
+        // Add hyperedge to hypergraph
+        hyperedges_->push_back(copy);
+        // Init hyperedge property
+        hyperedgeProperties_->push_back(new HyperedgeProperty());
+      }
+    }
+  } catch (std::bad_alloc& e) {
+    for (auto& hyperedge : *(hyperedges_.get())) {
+      delete hyperedge;
+    }
+    for (auto& hyperedgeProperty : *(hyperedgeProperties_.get())) {
+      delete hyperedgeProperty;
+    }
+    throw;
+  }
+}
+
 
 /**
  * \brief Copy assignment operator
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 634ab7f7cffc175dd6eac683fb3df5ece3a180ab..858acf75a2b94120986285e5f130e8099698a65c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -37,6 +37,7 @@ set(UNIT_TESTS_WITH_VALGRIND # Run these with valgrind (if available)
     testUndirectedHypergraph
     testUndirectedSubHypergraph
     testAlgorithmsDHG
+    testGraphConversion
     )
 set(UNIT_TESTS_WITHOUT_VALGRIND # Always run these without valgrind
     )
@@ -97,11 +98,6 @@ endforeach (UNIT_TEST)
 # ============================================================================
 find_package(Cpplint) # sets CPPLINT_FOUND and CPPLINT_PROGRAM
 if (CPPLINT_FOUND)
-  # List unit test source files
-  foreach (UNIT_TEST IN LISTS UNIT_TESTS)
-    list(APPEND UNIT_TEST_SOURCE_FILES ${hglib_SOURCE_DIR}/test/${UNIT_TEST}.cpp)
-  endforeach (UNIT_TEST)
-
   add_custom_target(run_cpplint
       COMMAND cpplint --extensions=h,hpp,cpp
       # filter runtime/explicit: requires explicit one argument constructor
diff --git a/test/testGraphConversion.cpp b/test/testGraphConversion.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..514da2429091de6cbcc3a28259890b6bd16819ff
--- /dev/null
+++ b/test/testGraphConversion.cpp
@@ -0,0 +1,301 @@
+// ****************************************************************************
+//
+//                          hglib - HyperGraph Library
+//
+// ****************************************************************************
+//
+// Copyright (C) 2018 Arnaud Mary, David Parsons, Martin Wannagat
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+// ****************************************************************************
+
+#include "hglib.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+using std::pair;
+using std::string;
+using std::vector;
+using std::cout;
+using std::endl;
+using hglib::DirectedVertex;
+using hglib::UndirectedVertex;
+using hglib::DirectedHyperedge;
+using hglib::UndirectedHyperedge;
+using hglib::NamedDirectedHyperedge;
+using hglib::NamedUndirectedHyperedge;
+
+class TestGraphConversion : public testing::Test {
+ protected:
+  virtual void SetUp() {
+  }
+
+  virtual void TearDown() {
+  }
+
+  vector<string> vertices {"A", "B", "Foo", "Bar", "", "6"};
+  vector<pair<vector<string>, string>> hyperedges {
+      {{"A", "Foo"}, "edge1"},
+      {{"A", "B", "Bar", ""}, "edge2"},
+      {{"6", ""}, "edge3"}
+  };
+  vector<pair<pair<vector<string>, vector<string>>, string>> hyperarcs {
+    {{{"A"}, {"Foo"}}, "edge1"},
+    {{{"A", "B"}, {"Bar", ""}}, "edge2"},
+    {{{"6"}, {""}}, "edge3"}
+  };
+};
+
+// Create ad-hoc properties
+enum class Colour {red, blue, green};
+struct VertexProperty {
+  Colour colour = Colour::green;
+};
+struct EdgeProperty {
+  double weight = 0.0;
+};
+struct GraphProperty {
+  std::string label;
+};
+
+TEST_F(TestGraphConversion, Test_DhgConversion) {
+  // Create a graph with no properties
+  hglib::DirectedHypergraph <DirectedVertex,
+                             DirectedHyperedge> g1;
+  for (auto vertexName : vertices) {
+    g1.addVertex(vertexName);
+  }
+  for (auto hyperarc : hyperarcs) {
+    g1.addHyperarc(hglib::NAME, hyperarc.first);
+  }
+
+  // Copy graph into graph with properties
+  hglib::DirectedHypergraph <DirectedVertex,
+                             DirectedHyperedge,
+                             VertexProperty,
+                             EdgeProperty,
+                             GraphProperty> g2(g1);
+
+  // Copy back into graph with empty properties
+  hglib::DirectedHypergraph <DirectedVertex,
+                             DirectedHyperedge,
+                             hglib::emptyProperty,
+                             hglib::emptyProperty,
+                             hglib::emptyProperty> g3(g2);
+
+  // Check nb of vertices and hyperarcs
+  ASSERT_EQ(g1.nbVertices(), g2.nbVertices());
+  ASSERT_EQ(g1.nbVertices(), g3.nbVertices());
+  ASSERT_EQ(g1.nbHyperarcs(), g2.nbHyperarcs());
+  ASSERT_EQ(g1.nbHyperarcs(), g3.nbHyperarcs());
+  // Check vertices
+  auto vertexIt = g1.verticesBegin();
+  auto vertexEnd = g1.verticesEnd();
+  for (; vertexIt != vertexEnd; ++vertexIt) {
+    const auto& g1Vertex = *vertexIt;
+    const auto& g2Vertex = g2.vertexByName(g1Vertex->name());
+    const auto& g3Vertex = g3.vertexByName(g1Vertex->name());
+    ASSERT_NE(g2Vertex, nullptr);
+    ASSERT_NE(g3Vertex, nullptr);
+    ASSERT_EQ(g1Vertex->id(), g2Vertex->id());
+    ASSERT_EQ(g1Vertex->id(), g3Vertex->id());
+    const auto& vertexId = g1Vertex->id();
+    // compare in-hyperarcs
+    ASSERT_EQ(g1.inDegree(vertexId), g2.inDegree(vertexId));
+    ASSERT_EQ(g1.inDegree(vertexId), g3.inDegree(vertexId));
+    auto hyperarcIt = g1.inHyperarcsBegin(vertexId);
+    auto hyperarcEnd = g1.inHyperarcsEnd(vertexId);
+    auto g2HyperarcIt = g2.inHyperarcsBegin(vertexId);
+    auto g3HyperarcIt = g3.inHyperarcsBegin(vertexId);
+    for (; hyperarcIt != hyperarcEnd; ++hyperarcIt) {
+      const auto& hyperarc = *hyperarcIt;
+      ASSERT_EQ(hyperarc->id(), (*g2HyperarcIt)->id());
+      ASSERT_EQ(hyperarc->id(), (*g3HyperarcIt)->id());
+      ++g2HyperarcIt;
+      ++g3HyperarcIt;
+    }
+    // compare out-edges
+    ASSERT_EQ(g1.outDegree(vertexId), g2.outDegree(vertexId));
+    ASSERT_EQ(g1.outDegree(vertexId), g3.outDegree(vertexId));
+    hyperarcIt = g1.outHyperarcsBegin(vertexId);
+    hyperarcEnd = g1.outHyperarcsEnd(vertexId);
+    g2HyperarcIt = g2.outHyperarcsBegin(vertexId);
+    g3HyperarcIt = g3.outHyperarcsBegin(vertexId);
+    for (; hyperarcIt != hyperarcEnd; ++hyperarcIt) {
+      const auto& hyperarc = *hyperarcIt;
+      ASSERT_EQ(hyperarc->id(), (*g2HyperarcIt)->id());
+      ASSERT_EQ(hyperarc->id(), (*g3HyperarcIt)->id());
+      ++g2HyperarcIt;
+      ++g3HyperarcIt;
+    }
+  }
+
+  // Check hyperarcs
+  auto itHyperarcs = g1.hyperarcsBegin();
+  auto itHyperarcsEnd = g1.hyperarcsEnd();
+  for (; itHyperarcs != itHyperarcsEnd; ++itHyperarcs) {
+    const auto& g1Hyperarc = *itHyperarcs;
+    const auto& g2Hyperarc = g2.hyperarcById(g1Hyperarc->id());
+    const auto& g3Hyperarc = g3.hyperarcById(g1Hyperarc->id());
+    ASSERT_NE(g2Hyperarc, nullptr);
+    ASSERT_NE(g3Hyperarc, nullptr);
+    ASSERT_EQ(g1Hyperarc->id(), g2Hyperarc->id());
+    ASSERT_EQ(g1Hyperarc->id(), g3Hyperarc->id());
+    const auto& g1HyperarcId = g1Hyperarc->id();
+    // compare tails
+    ASSERT_EQ(g1.nbTailVertices(g1HyperarcId), g2.nbTailVertices(g1HyperarcId));
+    ASSERT_EQ(g1.nbTailVertices(g1HyperarcId), g3.nbTailVertices(g1HyperarcId));
+    auto g2vertexIt = g2.tailsBegin(g1HyperarcId);
+    auto g3vertexIt = g3.tailsBegin(g1HyperarcId);
+    auto it = g1.tailsBegin(g1HyperarcId);
+    auto end = g1.tailsEnd(g1HyperarcId);
+    for (; it != end; ++it) {
+      const auto& tail = *it;
+      ASSERT_EQ(tail->id(), (*g2vertexIt)->id());
+      ASSERT_EQ(tail->id(), (*g3vertexIt)->id());
+      ASSERT_EQ(tail->name().compare((*g2vertexIt)->name()), 0);
+      ASSERT_EQ(tail->name().compare((*g3vertexIt)->name()), 0);
+      ++g2vertexIt;
+      ++g3vertexIt;
+    }
+    // compare heads
+    ASSERT_EQ(g1.nbHeadVertices(g1HyperarcId), g2.nbHeadVertices(g1HyperarcId));
+    ASSERT_EQ(g1.nbHeadVertices(g1HyperarcId), g3.nbHeadVertices(g1HyperarcId));
+    g2vertexIt = g2.headsBegin(g1HyperarcId);
+    g3vertexIt = g3.headsBegin(g1HyperarcId);
+
+    it = g1.headsBegin(g1HyperarcId);
+    end = g1.headsEnd(g1HyperarcId);
+    for (; it != end; ++it) {
+      const auto& head = *it;
+      ASSERT_EQ(head->id(), (*g2vertexIt)->id());
+      ASSERT_EQ(head->id(), (*g3vertexIt)->id());
+      ASSERT_EQ(head->name().compare((*g2vertexIt)->name()), 0);
+      ASSERT_EQ(head->name().compare((*g3vertexIt)->name()), 0);
+      ++g2vertexIt;
+      ++g3vertexIt;
+    }
+  }
+
+  // Add a vertex and hyperarc to converted graphs to check their correct id
+  const auto& g2AddedVertex = g2.addVertex("Test");
+  const auto& g3AddedVertex = g3.addVertex("Test");
+  const auto& g2AddedHyperarc = g2.addHyperarc(hglib::NAME, {{"A"}, {"Test"}});
+  const auto& g3AddedHyperarc = g3.addHyperarc(hglib::NAME, {{"A"}, {"Test"}});
+  ASSERT_EQ(g2AddedVertex->id(), 6);
+  ASSERT_EQ(g3AddedVertex->id(), 6);
+  ASSERT_EQ(g2AddedHyperarc->id(), 3);
+  ASSERT_EQ(g3AddedHyperarc->id(), 3);
+}
+
+TEST_F(TestGraphConversion, Test_UhgConversion) {
+  // Create a graph with no properties
+  hglib::UndirectedHypergraph<UndirectedVertex,
+                              UndirectedHyperedge> g1;
+  for (auto vertexName : vertices) {
+    g1.addVertex(vertexName);
+  }
+  for (auto hyperedge : hyperedges) {
+    g1.addHyperedge(hglib::NAME, hyperedge.first);
+  }
+
+  // Copy graph into graph with properties
+  hglib::UndirectedHypergraph<UndirectedVertex,
+                              UndirectedHyperedge,
+                              VertexProperty,
+                              EdgeProperty,
+                              GraphProperty> g2(g1);
+
+  // Copy back into graph with empty properties
+  hglib::UndirectedHypergraph<UndirectedVertex,
+                              UndirectedHyperedge,
+                              hglib::emptyProperty,
+                              hglib::emptyProperty,
+                              hglib::emptyProperty> g3(g2);
+  // Check nb of vertices and hyperarcs
+  ASSERT_EQ(g1.nbVertices(), g2.nbVertices());
+  ASSERT_EQ(g1.nbVertices(), g3.nbVertices());
+  ASSERT_EQ(g1.nbHyperedges(), g2.nbHyperedges());
+  ASSERT_EQ(g1.nbHyperedges(), g3.nbHyperedges());
+  // Check vertices
+  for (const auto& vertex : g1.vertices()) {
+    const auto& g2Vertex = g2.vertexByName(vertex->name());
+    const auto& g3Vertex = g3.vertexByName(vertex->name());
+    ASSERT_NE(g2Vertex, nullptr);
+    ASSERT_NE(g3Vertex, nullptr);
+    ASSERT_EQ(vertex->id(), g2Vertex->id());
+    ASSERT_EQ(vertex->id(), g3Vertex->id());
+    const auto& vertexId = vertex->id();
+    // Compare implied hyperedges
+    ASSERT_EQ(g1.nbHyperedges(vertexId), g2.nbHyperedges(vertexId));
+    ASSERT_EQ(g1.nbHyperedges(vertexId), g3.nbHyperedges(vertexId));
+    auto hyperedgeIt = g1.hyperedgesBegin(vertexId);
+    auto hyperedgeEnd = g1.hyperedgesEnd(vertexId);
+    auto g2HyperedgeIt = g2.hyperedgesBegin(vertexId);
+    auto g3HyperedgeIt = g3.hyperedgesBegin(vertexId);
+    for (; hyperedgeIt != hyperedgeEnd; ++hyperedgeIt) {
+      const auto& hyperedge = *hyperedgeIt;
+      ASSERT_EQ(hyperedge->id(), (*g2HyperedgeIt)->id());
+      ASSERT_EQ(hyperedge->id(), (*g3HyperedgeIt)->id());
+      ++g2HyperedgeIt;
+      ++g3HyperedgeIt;
+    }
+  }
+
+  // Check hyperedges
+  for (const auto& hyperedge : g1.hyperedges()) {
+    const auto& g2Hyperarc = g2.hyperedgeById(hyperedge->id());
+    const auto& g3Hyperarc = g3.hyperedgeById(hyperedge->id());
+    ASSERT_NE(g2Hyperarc, nullptr);
+    ASSERT_NE(g3Hyperarc, nullptr);
+    ASSERT_EQ(hyperedge->id(), g2Hyperarc->id());
+    ASSERT_EQ(hyperedge->id(), g3Hyperarc->id());
+    const auto& hyperedgeId = hyperedge->id();
+    // Compare impliedVertices
+    ASSERT_EQ(g1.nbImpliedVertices(hyperedgeId),
+              g2.nbImpliedVertices(hyperedgeId));
+    ASSERT_EQ(g1.nbImpliedVertices(hyperedgeId),
+              g3.nbImpliedVertices(hyperedgeId));
+    auto impliedVerticesIt = g1.impliedVerticesBegin(hyperedgeId);
+    auto impliedVerticesEnd = g1.impliedVerticesEnd(hyperedgeId);
+    auto g2VertexIt = g2.impliedVerticesBegin(hyperedgeId);
+    auto g3VertexIt = g3.impliedVerticesBegin(hyperedgeId);
+    for (; impliedVerticesIt != impliedVerticesEnd; ++impliedVerticesIt) {
+      const auto& v = *impliedVerticesIt;
+      ASSERT_EQ(v->id(), (*g2VertexIt)->id());
+      ASSERT_EQ(v->id(), (*g3VertexIt)->id());
+      ASSERT_EQ(v->name().compare((*g2VertexIt)->name()), 0);
+      ASSERT_EQ(v->name().compare((*g3VertexIt)->name()), 0);
+      ++g2VertexIt;
+      ++g3VertexIt;
+    }
+  }
+
+  // Add a vertex and hyperedge to converted graphs to check their correct id
+  const auto& g2AddedVertex = g2.addVertex("Test");
+  const auto& g3AddedVertex = g3.addVertex("Test");
+  const auto& g2AddedHyperedge = g2.addHyperedge(hglib::NAME,
+                                                 {"A", "Test"});
+  const auto& g3AddedHyperedge = g3.addHyperedge(hglib::NAME,
+                                                 {"A", "Test"});
+  ASSERT_EQ(g2AddedVertex->id(), 6);
+  ASSERT_EQ(g3AddedVertex->id(), 6);
+  ASSERT_EQ(g3AddedHyperedge->id(), 3);
+  ASSERT_EQ(g2AddedHyperedge->id(), 3);
+}
\ No newline at end of file