Ver Fonte

adjacency_matrix: directed/undirected tag

Michele Caini há 3 anos atrás
pai
commit
c1ac684f9a

+ 2 - 1
TODO

@@ -13,9 +13,10 @@ DOC:
 * update entity doc when the storage based model is in place
 
 WIP:
+* refine graph iterators a little
+* add directed/undirected support to dot
 * dense_map/set and registry: move ctor/op should be noexcept (op is conditionally noexcept though)
 * "replace" organizer with flow
-* add directed/undirected support to adjacency matrix (see brief) and refine iterators a little
 * add storage getter for filters to views and groups
 * exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
 * emitter: runtime handlers, allocator support (ready for both already)

+ 38 - 19
src/entt/graph/adjacency_matrix.hpp

@@ -155,11 +155,13 @@ template<typename Container>
 
 /**
  * @brief Basic implementation of a directed adjacency matrix.
+ * @tparam Category Either a directed or undirected category tag.
  * @tparam Allocator Type of allocator used to manage memory and elements.
  */
-template<typename Allocator>
-class basic_adjacency_matrix {
+template<typename Category, typename Allocator>
+class adjacency_matrix {
     using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_base_of_v<undirected_tag, Category>, "Invalid graph category");
     static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
     using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
 
@@ -180,17 +182,19 @@ public:
     using out_edge_iterator = internal::row_edge_iterator<typename container_type::const_iterator>;
     /*! @brief In edge iterator type. */
     using in_edge_iterator = internal::col_edge_iterator<typename container_type::const_iterator>;
+    /*! @brieg Graph category tag. */
+    using graph_category = Category;
 
     /*! @brief Default constructor. */
-    basic_adjacency_matrix() noexcept(noexcept(allocator_type{}))
-        : basic_adjacency_matrix{0u} {}
+    adjacency_matrix() noexcept(noexcept(allocator_type{}))
+        : adjacency_matrix{0u} {}
 
     /**
      * @brief Constructs an empty container with a given allocator.
      * @param allocator The allocator to use.
      */
-    explicit basic_adjacency_matrix(const allocator_type &allocator) noexcept
-        : basic_adjacency_matrix{0u, allocator} {}
+    explicit adjacency_matrix(const allocator_type &allocator) noexcept
+        : adjacency_matrix{0u, allocator} {}
 
     /**
      * @brief Constructs an empty container with a given allocator and user
@@ -198,7 +202,7 @@ public:
      * @param vertices Number of vertices.
      * @param allocator The allocator to use.
      */
-    basic_adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
+    adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
         : matrix(vertices * vertices),
           vert{vertices} {}
 
@@ -206,15 +210,15 @@ public:
      * @brief Copy constructor.
      * @param other The instance to copy from.
      */
-    basic_adjacency_matrix(const basic_adjacency_matrix &other)
-        : basic_adjacency_matrix{other, other.get_allocator()} {}
+    adjacency_matrix(const adjacency_matrix &other)
+        : adjacency_matrix{other, other.get_allocator()} {}
 
     /**
      * @brief Allocator-extended copy constructor.
      * @param other The instance to copy from.
      * @param allocator The allocator to use.
      */
-    basic_adjacency_matrix(const basic_adjacency_matrix &other, const allocator_type &allocator)
+    adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
         : matrix{other.matrix, allocator},
           vert{other.vert} {}
 
@@ -222,15 +226,15 @@ public:
      * @brief Move constructor.
      * @param other The instance to move from.
      */
-    basic_adjacency_matrix(basic_adjacency_matrix &&other) noexcept
-        : basic_adjacency_matrix{std::move(other), other.get_allocator()} {}
+    adjacency_matrix(adjacency_matrix &&other) noexcept
+        : adjacency_matrix{std::move(other), other.get_allocator()} {}
 
     /**
      * @brief Allocator-extended move constructor.
      * @param other The instance to move from.
      * @param allocator The allocator to use.
      */
-    basic_adjacency_matrix(basic_adjacency_matrix &&other, const allocator_type &allocator)
+    adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
         : matrix{std::move(other.matrix), allocator},
           vert{std::exchange(other.vert, 0u)} {}
 
@@ -239,7 +243,7 @@ public:
      * @param other The instance to copy from.
      * @return This container.
      */
-    basic_adjacency_matrix &operator=(const basic_adjacency_matrix &other) {
+    adjacency_matrix &operator=(const adjacency_matrix &other) {
         matrix = other.matrix;
         vert = other.vert;
         return *this;
@@ -250,7 +254,7 @@ public:
      * @param other The instance to move from.
      * @return This container.
      */
-    basic_adjacency_matrix &operator=(basic_adjacency_matrix &&other) noexcept {
+    adjacency_matrix &operator=(adjacency_matrix &&other) noexcept {
         matrix = std::move(other.matrix);
         vert = std::exchange(other.vert, 0u);
         return *this;
@@ -274,7 +278,7 @@ public:
      * @brief Exchanges the contents with those of a given adjacency matrix.
      * @param other Adjacency matrix to exchange the content with.
      */
-    void swap(basic_adjacency_matrix &other) {
+    void swap(adjacency_matrix &other) {
         using std::swap;
         swap(matrix, other.matrix);
         swap(vert, other.vert);
@@ -326,7 +330,7 @@ public:
     [[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
         const auto it = matrix.cbegin();
         const auto from = vertex;
-        const auto to = vertex * vert + vertex;
+        const auto to = vert * (vert - 1u) + vertex;
         return {{it, vert, from, to}, {it, vert, to, to}};
     }
 
@@ -335,7 +339,7 @@ public:
      * @param vertices The new number of vertices.
      */
     void resize(const size_type vertices) {
-        basic_adjacency_matrix other{vertices, get_allocator()};
+        adjacency_matrix other{vertices, get_allocator()};
 
         for(auto [lhs, rhs]: edges()) {
             other.insert(lhs, rhs);
@@ -354,6 +358,13 @@ public:
      */
     std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
         const auto pos = lhs * vert + rhs;
+
+        if constexpr(std::is_same_v<graph_category, undirected_tag>) {
+            const auto rev = rhs * vert + lhs;
+            ENTT_ASSERT(matrix[pos] == matrix[rev]);
+            matrix[rev] = 1u;
+        }
+
         const auto inserted = !std::exchange(matrix[pos], 1u);
         return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size()}, inserted};
     }
@@ -365,7 +376,15 @@ public:
      * @return Number of elements removed (either 0 or 1).
      */
     size_type erase(const vertex_type lhs, const vertex_type rhs) {
-        return std::exchange(matrix[lhs * vert + rhs], 0u);
+        const auto pos = lhs * vert + rhs;
+
+        if constexpr(std::is_same_v<graph_category, undirected_tag>) {
+            const auto rev = rhs * vert + lhs;
+            ENTT_ASSERT(matrix[pos] == matrix[rev]);
+            matrix[rev] = 0u;
+        }
+
+        return std::exchange(matrix[pos], 0u);
     }
 
     /**

+ 2 - 2
src/entt/graph/flow.hpp

@@ -233,9 +233,9 @@ public:
      * @brief Generates a task graph for the current content.
      * @return The adjacency matrix of the task graph.
      */
-    adjacency_matrix graph() const {
+    adjacency_matrix<directed_tag> graph() const {
         const auto length = vertices.size();
-        adjacency_matrix matrix{length};
+        adjacency_matrix<directed_tag> matrix{length};
 
         // creates the adjacency matrix
         for(const auto &elem: deps) {

+ 8 - 5
src/entt/graph/fwd.hpp

@@ -7,15 +7,18 @@
 
 namespace entt {
 
-template<typename = std::allocator<std::size_t>>
-class basic_adjacency_matrix;
+/*! @brief Undirected graph category tag. */
+struct undirected_tag {};
+
+/*! @brief Directed graph category tag. */
+struct directed_tag: undirected_tag {};
+
+template<typename, typename = std::allocator<std::size_t>>
+class adjacency_matrix;
 
 template<typename = std::allocator<id_type>>
 class basic_flow;
 
-/*! @brief Alias declaration for the most common use case. */
-using adjacency_matrix = basic_adjacency_matrix<>;
-
 /*! @brief Alias declaration for the most common use case. */
 using flow = basic_flow<>;
 

+ 154 - 29
test/entt/graph/adjacency_matrix.cpp

@@ -5,7 +5,7 @@
 #include "../common/throwing_allocator.hpp"
 
 TEST(AdjacencyMatrix, Resize) {
-    entt::adjacency_matrix adjacency_matrix{2};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2};
     adjacency_matrix.insert(1u, 0u);
 
     ASSERT_EQ(adjacency_matrix.size(), 2u);
@@ -18,19 +18,19 @@ TEST(AdjacencyMatrix, Resize) {
 }
 
 TEST(AdjacencyMatrix, Constructors) {
-    entt::adjacency_matrix adjacency_matrix{};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
 
     ASSERT_EQ(adjacency_matrix.size(), 0u);
 
-    adjacency_matrix = entt::adjacency_matrix{std::allocator<bool>{}};
-    adjacency_matrix = entt::adjacency_matrix{3u, std::allocator<bool>{}};
+    adjacency_matrix = entt::adjacency_matrix<entt::directed_tag>{std::allocator<bool>{}};
+    adjacency_matrix = entt::adjacency_matrix<entt::directed_tag>{3u, std::allocator<bool>{}};
 
     ASSERT_EQ(adjacency_matrix.size(), 3u);
 
     adjacency_matrix.insert(0u, 1u);
 
-    entt::adjacency_matrix temp{adjacency_matrix, adjacency_matrix.get_allocator()};
-    entt::adjacency_matrix other{std::move(adjacency_matrix), adjacency_matrix.get_allocator()};
+    entt::adjacency_matrix<entt::directed_tag> temp{adjacency_matrix, adjacency_matrix.get_allocator()};
+    entt::adjacency_matrix<entt::directed_tag> other{std::move(adjacency_matrix), adjacency_matrix.get_allocator()};
 
     ASSERT_EQ(adjacency_matrix.size(), 0u);
     ASSERT_EQ(other.size(), 3u);
@@ -40,10 +40,10 @@ TEST(AdjacencyMatrix, Constructors) {
 }
 
 TEST(AdjacencyMatrix, Copy) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
     adjacency_matrix.insert(0u, 1u);
 
-    entt::adjacency_matrix other{adjacency_matrix};
+    entt::adjacency_matrix<entt::directed_tag> other{adjacency_matrix};
 
     ASSERT_EQ(adjacency_matrix.size(), 3u);
     ASSERT_EQ(other.size(), 3u);
@@ -66,10 +66,10 @@ TEST(AdjacencyMatrix, Copy) {
 }
 
 TEST(AdjacencyMatrix, Move) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
     adjacency_matrix.insert(0u, 1u);
 
-    entt::adjacency_matrix other{std::move(adjacency_matrix)};
+    entt::adjacency_matrix<entt::directed_tag> other{std::move(adjacency_matrix)};
 
     ASSERT_EQ(adjacency_matrix.size(), 0u);
     ASSERT_EQ(other.size(), 3u);
@@ -93,8 +93,8 @@ TEST(AdjacencyMatrix, Move) {
 }
 
 TEST(AdjacencyMatrix, Swap) {
-    entt::adjacency_matrix adjacency_matrix{3u};
-    entt::adjacency_matrix other{};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> other{};
 
     adjacency_matrix.insert(0u, 1u);
 
@@ -111,8 +111,8 @@ TEST(AdjacencyMatrix, Swap) {
     ASSERT_TRUE(other.contains(0u, 1u));
 }
 
-TEST(AdjacencyMatrix, Insert) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+TEST(AdjacencyMatrix, InsertDirected) {
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
 
     auto first = adjacency_matrix.insert(0u, 1u);
     auto second = adjacency_matrix.insert(0u, 2u);
@@ -127,21 +127,64 @@ TEST(AdjacencyMatrix, Insert) {
 
     ASSERT_EQ(*first.first, std::make_pair(std::size_t{0u}, std::size_t{1u}));
     ASSERT_EQ(*second.first, std::make_pair(std::size_t{0u}, std::size_t{2u}));
+
+    ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_FALSE(adjacency_matrix.contains(2u, 0u));
+}
+
+TEST(AdjacencyMatrix, InsertUndirected) {
+    entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
+
+    auto first = adjacency_matrix.insert(0u, 1u);
+    auto second = adjacency_matrix.insert(0u, 2u);
+    auto other = adjacency_matrix.insert(0u, 1u);
+
+    ASSERT_TRUE(first.second);
+    ASSERT_TRUE(second.second);
+    ASSERT_FALSE(other.second);
+
+    ASSERT_NE(first.first, second.first);
+    ASSERT_EQ(first.first, other.first);
+
+    ASSERT_EQ(*first.first, std::make_pair(std::size_t{0u}, std::size_t{1u}));
+    ASSERT_EQ(*second.first, std::make_pair(std::size_t{0u}, std::size_t{2u}));
+
+    ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_TRUE(adjacency_matrix.contains(2u, 0u));
+}
+
+TEST(AdjacencyMatrix, EraseDirected) {
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
+
+    adjacency_matrix.insert(0u, 1u);
+
+    ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
+
+    ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 1u);
+    ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 0u);
+
+    ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
 }
 
-TEST(AdjacencyMatrix, Erase) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+TEST(AdjacencyMatrix, EraseUndirected) {
+    entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
 
     adjacency_matrix.insert(0u, 1u);
 
     ASSERT_TRUE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_TRUE(adjacency_matrix.contains(1u, 0u));
+
     ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 1u);
     ASSERT_EQ(adjacency_matrix.erase(0u, 1u), 0u);
+
     ASSERT_FALSE(adjacency_matrix.contains(0u, 1u));
+    ASSERT_FALSE(adjacency_matrix.contains(1u, 0u));
 }
 
 TEST(AdjacencyMatrix, Clear) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
 
     adjacency_matrix.insert(0u, 1u);
     adjacency_matrix.insert(0u, 2u);
@@ -158,13 +201,13 @@ TEST(AdjacencyMatrix, Clear) {
 }
 
 TEST(AdjacencyMatrix, VertexIterator) {
-    using iterator = typename entt::adjacency_matrix::vertex_iterator;
+    using iterator = typename entt::adjacency_matrix<entt::directed_tag>::vertex_iterator;
 
     static_assert(std::is_same_v<iterator::value_type, std::size_t>);
     static_assert(std::is_same_v<iterator::pointer, void>);
     static_assert(std::is_same_v<iterator::reference, std::size_t>);
 
-    entt::adjacency_matrix adjacency_matrix{2u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{2u};
     const auto iterable = adjacency_matrix.vertices();
 
     iterator end{iterable.begin()};
@@ -184,13 +227,13 @@ TEST(AdjacencyMatrix, VertexIterator) {
 }
 
 TEST(AdjacencyMatrix, EdgeIterator) {
-    using iterator = typename entt::adjacency_matrix::edge_iterator;
+    using iterator = typename entt::adjacency_matrix<entt::directed_tag>::edge_iterator;
 
     static_assert(std::is_same_v<iterator::value_type, std::pair<std::size_t, std::size_t>>);
     static_assert(std::is_same_v<iterator::pointer, entt::input_iterator_pointer<std::pair<std::size_t, std::size_t>>>);
     static_assert(std::is_same_v<iterator::reference, std::pair<std::size_t, std::size_t>>);
 
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
 
     adjacency_matrix.insert(0u, 1u);
     adjacency_matrix.insert(0u, 2u);
@@ -214,7 +257,7 @@ TEST(AdjacencyMatrix, EdgeIterator) {
 }
 
 TEST(AdjacencyMatrix, Vertices) {
-    entt::adjacency_matrix adjacency_matrix{};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
     auto iterable = adjacency_matrix.vertices();
 
     ASSERT_EQ(adjacency_matrix.size(), 0u);
@@ -233,8 +276,8 @@ TEST(AdjacencyMatrix, Vertices) {
     ASSERT_EQ(++it, iterable.end());
 }
 
-TEST(AdjacencyMatrix, Edges) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+TEST(AdjacencyMatrix, EdgesDirected) {
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
     auto iterable = adjacency_matrix.edges();
 
     ASSERT_EQ(iterable.begin(), iterable.end());
@@ -252,8 +295,30 @@ TEST(AdjacencyMatrix, Edges) {
     ASSERT_EQ(++it, iterable.end());
 }
 
-TEST(AdjacencyMatrix, OutEdges) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+TEST(AdjacencyMatrix, EdgesUndirected) {
+    entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
+    auto iterable = adjacency_matrix.edges();
+
+    ASSERT_EQ(iterable.begin(), iterable.end());
+
+    adjacency_matrix.insert(0u, 1u);
+    adjacency_matrix.insert(1u, 2u);
+    iterable = adjacency_matrix.edges();
+
+    ASSERT_NE(iterable.begin(), iterable.end());
+
+    auto it = iterable.begin();
+
+    ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
+    ASSERT_EQ(*it.operator->(), std::make_pair(std::size_t{1u}, std::size_t{0u}));
+    ASSERT_EQ(*(++it).operator->(), std::make_pair(std::size_t{1u}, std::size_t{2u}));
+    ASSERT_EQ(*++it, std::make_pair(std::size_t{2u}, std::size_t{1u}));
+
+    ASSERT_EQ(++it, iterable.end());
+}
+
+TEST(AdjacencyMatrix, OutEdgesDirected) {
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
     auto iterable = adjacency_matrix.out_edges(0u);
 
     ASSERT_EQ(iterable.begin(), iterable.end());
@@ -268,10 +333,63 @@ TEST(AdjacencyMatrix, OutEdges) {
 
     ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
     ASSERT_EQ(it, iterable.end());
+
+    iterable = adjacency_matrix.out_edges(2u);
+    it = iterable.cbegin();
+
+    ASSERT_EQ(it, iterable.cend());
 }
 
-TEST(AdjacencyMatrix, InEdges) {
-    entt::adjacency_matrix adjacency_matrix{3u};
+TEST(AdjacencyMatrix, OutEdgesUndirected) {
+    entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
+    auto iterable = adjacency_matrix.out_edges(0u);
+
+    ASSERT_EQ(iterable.begin(), iterable.end());
+
+    adjacency_matrix.insert(0u, 1u);
+    adjacency_matrix.insert(1u, 2u);
+    iterable = adjacency_matrix.out_edges(0u);
+
+    ASSERT_NE(iterable.begin(), iterable.end());
+
+    auto it = iterable.begin();
+
+    ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
+    ASSERT_EQ(it, iterable.end());
+
+    iterable = adjacency_matrix.out_edges(2u);
+    it = iterable.cbegin();
+
+    ASSERT_NE(it, iterable.cend());
+    ASSERT_EQ(*it++, std::make_pair(std::size_t{2u}, std::size_t{1u}));
+    ASSERT_EQ(it, iterable.cend());
+}
+
+TEST(AdjacencyMatrix, InEdgesDirected) {
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
+    auto iterable = adjacency_matrix.in_edges(1u);
+
+    ASSERT_EQ(iterable.begin(), iterable.end());
+
+    adjacency_matrix.insert(0u, 1u);
+    adjacency_matrix.insert(1u, 2u);
+    iterable = adjacency_matrix.in_edges(1u);
+
+    ASSERT_NE(iterable.begin(), iterable.end());
+
+    auto it = iterable.begin();
+
+    ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
+    ASSERT_EQ(it, iterable.end());
+
+    iterable = adjacency_matrix.in_edges(0u);
+    it = iterable.cbegin();
+
+    ASSERT_EQ(it, iterable.cend());
+}
+
+TEST(AdjacencyMatrix, InEdgesUndirected) {
+    entt::adjacency_matrix<entt::undirected_tag> adjacency_matrix{3u};
     auto iterable = adjacency_matrix.in_edges(1u);
 
     ASSERT_EQ(iterable.begin(), iterable.end());
@@ -286,13 +404,20 @@ TEST(AdjacencyMatrix, InEdges) {
 
     ASSERT_EQ(*it++, std::make_pair(std::size_t{0u}, std::size_t{1u}));
     ASSERT_EQ(it, iterable.end());
+
+    iterable = adjacency_matrix.in_edges(0u);
+    it = iterable.cbegin();
+
+    ASSERT_NE(it, iterable.cend());
+    ASSERT_EQ(*it++, std::make_pair(std::size_t{1u}, std::size_t{0u}));
+    ASSERT_EQ(it, iterable.cend());
 }
 
 TEST(AdjacencyMatrix, ThrowingAllocator) {
     using allocator = test::throwing_allocator<std::size_t>;
     using exception = typename allocator::exception_type;
 
-    entt::basic_adjacency_matrix<allocator> adjacency_matrix{2u};
+    entt::adjacency_matrix<entt::directed_tag, allocator> adjacency_matrix{2u};
     adjacency_matrix.insert(0u, 1u);
 
     allocator::trigger_on_allocate = true;

+ 2 - 2
test/entt/graph/dot.cpp

@@ -6,7 +6,7 @@
 
 TEST(Dot, DefaultWriter) {
     std::ostringstream output{};
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
 
     adjacency_matrix.insert(0u, 1u);
     adjacency_matrix.insert(1u, 2u);
@@ -23,7 +23,7 @@ TEST(Dot, DefaultWriter) {
 
 TEST(Dot, CustomWriter) {
     std::ostringstream output{};
-    entt::adjacency_matrix adjacency_matrix{3u};
+    entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
 
     adjacency_matrix.insert(0u, 1u);
     adjacency_matrix.insert(1u, 2u);