Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/semigroups/libsemigroups/tests/   (GAP Algebra Version 4.15.1©)  Datei vom 18.5.2025 mit Größe 71 kB image not shown  

Quelle  test-digraph.cpp

  Sprache: C
 

//
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2019 Finn Smith
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

// TODO(v3):
// * renumber the tests

#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER

#include <cstddef>        // for size_t
#include <stdexcept>      // for runtime_error
#include <unordered_set>  // for unordered_set
#include <vector>         // for vector

#include "catch.hpp"  // for REQUIRE, REQUIRE_THROWS_AS, REQUI...
#include "libsemigroups/digraph-helper.hpp"  // for follow_path
#include "libsemigroups/digraph.hpp"         // for ActionDigraph
#include "libsemigroups/forest.hpp"          // for Forest
#include "libsemigroups/kbe.hpp"             // for KBE
#include "libsemigroups/knuth-bendix.hpp"    // for KnuthBendix
#include "libsemigroups/wilo.hpp"            // for cbegin_wilo
#include "libsemigroups/wislo.hpp"           // for cbegin_wislo
#include "test-main.hpp"                     // for LIBSEMIGROUPS_TEST_CASE

CATCH_REGISTER_ENUM(libsemigroups::ActionDigraph<size_t>::algorithm,
                    libsemigroups::ActionDigraph<size_t>::algorithm::dfs,
                    libsemigroups::ActionDigraph<size_t>::algorithm::matrix,
                    libsemigroups::ActionDigraph<size_t>::algorithm::acyclic,
                    libsemigroups::ActionDigraph<size_t>::algorithm::automatic,
                    libsemigroups::ActionDigraph<size_t>::algorithm::trivial)

namespace libsemigroups {
  using KnuthBendix = fpsemigroup::KnuthBendix;

  struct LibsemigroupsException;  // forward decl

  namespace {
    void add_chain(ActionDigraph<size_t>& digraph, size_t n) {
      size_t old_nodes = digraph.number_of_nodes();
      digraph.add_nodes(n);
      for (size_t i = old_nodes; i < digraph.number_of_nodes() - 1; ++i) {
        digraph.add_edge(i, i + 10);
      }
    }

    ActionDigraph<size_t> chain(size_t n) {
      ActionDigraph<size_t> g(01);
      add_chain(g, n);
      return g;
    }

    void add_clique(ActionDigraph<size_t>& digraph, size_t n) {
      if (n != digraph.out_degree()) {
        throw std::runtime_error("can't do it!");
      }
      size_t old_nodes = digraph.number_of_nodes();
      digraph.add_nodes(n);

      for (size_t i = old_nodes; i < digraph.number_of_nodes(); ++i) {
        for (size_t j = old_nodes; j < digraph.number_of_nodes(); ++j) {
          digraph.add_edge(i, j, j - old_nodes);
        }
      }
    }

    ActionDigraph<size_t> clique(size_t n) {
      ActionDigraph<size_t> g(0, n);
      add_clique(g, n);
      return g;
    }

    ActionDigraph<size_t> binary_tree(size_t number_of_levels) {
      ActionDigraph<size_t> ad;
      ad.add_nodes(std::pow(2, number_of_levels) - 1);
      ad.add_to_out_degree(2);
      ad.add_edge(010);
      ad.add_edge(021);

      for (size_t i = 2; i <= number_of_levels; ++i) {
        size_t counter = std::pow(2, i - 1) - 1;
        for (size_t j = std::pow(2, i - 2) - 1; j < std::pow(2, i - 1) - 1;
             ++j) {
          ad.add_edge(j, counter++, 0);
          ad.add_edge(j, counter++, 1);
        }
      }
      return ad;
    }
  }  // namespace

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "000",
                          "constructor with 1  default arg",
                          "[quick][digraph]") {
    ActionDigraph<size_t> g;
    REQUIRE(g.number_of_nodes() == 0);
    REQUIRE(g.number_of_edges() == 0);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "001",
                          "constructor with 0 default args",
                          "[quick][digraph]") {
    for (size_t j = 0; j < 100; ++j) {
      ActionDigraph<size_t> g(j);
      REQUIRE(g.number_of_nodes() == j);
      REQUIRE(g.number_of_edges() == 0);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "002",
                          "add nodes",
                          "[quick][digraph]") {
    ActionDigraph<size_t> g(3);
    REQUIRE(g.number_of_nodes() == 3);
    REQUIRE(g.number_of_edges() == 0);

    for (size_t i = 1; i < 100; ++i) {
      g.add_nodes(i);
      REQUIRE(g.number_of_nodes() == 3 + i * (i + 1) / 2);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "003",
                          "add edges",
                          "[quick][digraph]") {
    ActionDigraph<size_t> g(1731);

    for (size_t i = 0; i < 17; ++i) {
      // The digraph isn't fully defined
      REQUIRE_NOTHROW(g.number_of_scc());
      for (size_t j = 0; j < 31; ++j) {
        g.add_edge(i, (7 * i + 23 * j) % 17, j);
      }
    }

    REQUIRE(g.number_of_edges() == 31 * 17);
    REQUIRE(g.number_of_nodes() == 17);
    REQUIRE_THROWS_AS(g.add_edge(0032), LibsemigroupsException);

    for (size_t i = 0; i < 17; ++i) {
      for (size_t j = 0; j < 31; ++j) {
        REQUIRE(g.neighbor(i, j) == (7 * i + 23 * j) % 17);
      }
    }

    g.add_to_out_degree(10);
    REQUIRE(g.out_degree() == 41);
    REQUIRE(g.number_of_nodes() == 17);
    REQUIRE(!g.validate());

    for (size_t i = 0; i < 17; ++i) {
      for (size_t j = 0; j < 10; ++j) {
        g.add_edge(i, (7 * i + 23 * j) % 1731 + j);
      }
    }

    REQUIRE(g.number_of_edges() == 41 * 17);
    REQUIRE(g.number_of_nodes() == 17);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "004",
                          "strongly connected components - cycles",
                          "[quick][digraph]") {
    ActionDigraph<size_t> g;
    g.add_to_out_degree(1);
    action_digraph_helper::add_cycle(g, 32);
    REQUIRE(g.scc_id(0) == 0);
    g = ActionDigraph<size_t>();
    g.add_to_out_degree(1);
    action_digraph_helper::add_cycle(g, 33);
    REQUIRE(std::vector<std::vector<size_t>>(g.cbegin_sccs(), g.cend_sccs())
            == std::vector<std::vector<size_t>>(
                {{3231302928272625242322,
                  2120191817161514131211,
                  109,  8,  7,  6,  5,  4,  3,  2,  1,  0}}));
    for (size_t i = 0; i < 33; ++i) {
      REQUIRE(g.scc_id(i) == 0);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "005",
                          "strongly connected components - no edges",
                          "[quick][digraph][no-valgrind]") {
    ActionDigraph<size_t> graph = ActionDigraph<size_t>(0);
    for (size_t j = 1; j < 100; ++j) {
      graph.add_nodes(j);

      for (size_t i = 0; i < j * (j + 1) / 2; ++i) {
        REQUIRE(graph.scc_id(i) == i);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "006",
                          "strongly connected components - disjoint cycles",
                          "[quick][digraph]") {
    ActionDigraph<size_t> g;
    g.add_to_out_degree(1);
    using difference_type = typename std::iterator_traits<
        ActionDigraph<size_t>::const_iterator_nodes>::difference_type;
    for (size_t j = 2; j < 50; ++j) {
      action_digraph_helper::add_cycle(g, j);
      REQUIRE(std::count_if(
                  g.cbegin_nodes(),
                  g.cend_nodes(),
                  [&g, j](size_t nd) -> bool { return g.scc_id(nd) == j - 2; })
              == difference_type(j));
    }

    REQUIRE(g.number_of_nodes() == 1224);
    REQUIRE(g.number_of_edges() == 1224);
    REQUIRE(g.validate());
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "007",
                          "strongly connected components - complete graphs",
                          "[quick][digraph]") {
    for (size_t k = 2; k < 50; ++k) {
      ActionDigraph<size_t> graph(k, k);

      for (size_t i = 0; i < k; ++i) {
        for (size_t j = 0; j < k; ++j) {
          // might as well leave the loops in
          graph.add_edge(i, j, j);
        }
      }
      for (size_t i = 0; i < k; ++i) {
        REQUIRE(graph.scc_id(i) == 0);
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "008",
                          "exceptions",
                          "[quick][digraph]") {
    ActionDigraph<size_t> graph(105);
    REQUIRE_THROWS_AS(graph.neighbor(100), LibsemigroupsException);
    REQUIRE(graph.neighbor(01) == UNDEFINED);

    REQUIRE_THROWS_AS(graph.add_edge(0100), LibsemigroupsException);
    REQUIRE_THROWS_AS(graph.add_edge(1000), LibsemigroupsException);
    for (size_t i = 0; i < 5; ++i) {
      graph.add_edge(01, i);
      graph.add_edge(22, i);
    }
    REQUIRE_NOTHROW(graph.add_edge(010));
    REQUIRE_NOTHROW(graph.add_edge(220));

    REQUIRE_THROWS_AS(graph.scc_id(10), LibsemigroupsException);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "009",
                          "spanning forest - complete graphs",
                          "[quick][digraph]") {
    for (size_t k = 2; k < 50; ++k) {
      ActionDigraph<size_t> graph(k, k);

      for (size_t i = 0; i < k; ++i) {
        for (size_t j = 0; j < k; ++j) {
          // might as well leave the loops in
          graph.add_edge(i, j, j);
        }
      }
      REQUIRE(graph.number_of_scc() == 1);

      Forest const& forest = graph.spanning_forest();
      REQUIRE(forest.parent(k - 1) == UNDEFINED);
      REQUIRE_NOTHROW(graph.reverse_spanning_forest());
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "010",
                          "spanning forest - disjoint cycles",
                          "[quick][digraph]") {
    size_t                j = 33;
    ActionDigraph<size_t> graph;
    graph.add_to_out_degree(1);

    for (size_t k = 0; k < 10; ++k) {
      graph.add_nodes(j);
      for (size_t i = k * j; i < (k + 1) * j - 1; ++i) {
        graph.add_edge(i, i + 10);
      }
      graph.add_edge((k + 1) * j - 1, k * j, 0);
    }
    for (size_t i = 0; i < 10 * j; ++i) {
      REQUIRE(graph.scc_id(i) == i / j);
    }
    Forest forest = graph.spanning_forest();

    REQUIRE(std::vector<size_t>(forest.cbegin_parent(), forest.cend_parent())
            == std::vector<size_t>(
                {32,  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
                 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,  20,
                 21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  UNDEFINED,
                 65,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
                 43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,
                 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  UNDEFINED,
                 98,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,
                 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,
                 87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  UNDEFINED,
                 13199,  100101102103104105106107108,
                 109110111112113114115116117118119,
                 120121122123124125126127128129, UNDEFINED,
                 164132133134135136137138139140141,
                 142143144145146147148149150151152,
                 153154155156157158159160161162, UNDEFINED,
                 197165166167168169170171172173174,
                 175176177178179180181182183184185,
                 186187188189190191192193194195, UNDEFINED,
                 230198199200201202203204205206207,
                 208209210211212213214215216217218,
                 219220221222223224225226227228, UNDEFINED,
                 263231232233234235236237238239240,
                 241242243244245246247248249250251,
                 252253254255256257258259260261, UNDEFINED,
                 296264265266267268269270271272273,
                 274275276277278279280281282283284,
                 285286287288289290291292293294, UNDEFINED,
                 329297298299300301302303304305306,
                 307308309310311312313314315316317,
                 318319320321322323324325326327, UNDEFINED}));
  }

  // TODO(FLS) uncomment this
  //  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
  //                          "011",
  //                          "scc root paths - complete graphs",
  //                          "[quick][digraph]") {
  //    for (size_t k = 2; k < 50; ++k) {
  //      ActionDigraph<size_t> graph(k);
  //
  //      for (size_t i = 0; i < k; ++i) {
  //        for (size_t j = 0; j < k; ++j) {
  //          graph.add_edge(i, j, j);
  //        }
  //      }
  //
  //      for (size_t i = 0; i < k; ++i) {
  //        size_t pos = i;
  //        for (auto it = graph.cbegin_path_to_root(i); it <
  //        graph.cend_path_to_root(i); ++it) {
  //          pos = graph.neighbor(pos, *it);
  //        }
  //        REQUIRE(pos == graph.cbegin_sccs()[graph.scc_id(i)][0]);
  //      }
  //    }
  //  }

  // LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
  //                         "012",
  //                         "scc root paths - disjoint cycles",
  //                         "[quick][digraph]") {
  //   for (size_t j = 2; j < 35; ++j) {
  //     ActionDigraph<size_t> graph;

  //     for (size_t k = 0; k < 6; ++k) {
  //       graph.add_nodes(j);
  //       for (size_t i = k * j; i < (k + 1) * j - 1; ++i) {
  //         graph.add_edge(i, i + 1, 0);
  //       }
  //       graph.add_edge((k + 1) * j - 1, k * j, 0);
  //     }

  //     for (size_t i = 0; i < graph.number_of_nodes(); ++i) {
  //       size_t pos = i;
  //       for (auto it = graph.cbegin_path_to_root(i);
  //            it < graph.cend_path_to_root(i);
  //            ++it) {
  //         pos = graph.neighbor(pos, *it);
  //       }
  //       REQUIRE(pos == graph.cbegin_sccs()[graph.scc_id(i)][0]);
  //     }
  //   }
  // }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "013",
                          "scc large cycle",
                          "[quick][digraph]") {
    ActionDigraph<size_t> graph;
    graph.add_to_out_degree(1);
    action_digraph_helper::add_cycle(graph, 100000);
    using node_type = decltype(graph)::node_type;

    REQUIRE(std::all_of(
        graph.cbegin_nodes(),
        graph.cend_nodes(),
        [&graph](node_type i) -> bool { return graph.scc_id(i) == 0; }));
    action_digraph_helper::add_cycle(graph, 10101);
    REQUIRE(std::all_of(
        graph.cbegin_nodes(),
        graph.cend_nodes() - 10101,
        [&graph](node_type i) -> bool { return graph.scc_id(i) == 0; }));
    REQUIRE(std::all_of(
        graph.cbegin_nodes() + 100000,
        graph.cend_nodes(),
        [&graph](node_type i) -> bool { return graph.scc_id(i) == 1; }));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "014",
                          "random",
                          "[quick][digraph]") {
    ActionDigraph<size_t> graph = ActionDigraph<size_t>::random(1010);
    REQUIRE(graph.number_of_nodes() == 10);
    REQUIRE(graph.number_of_edges() == 100);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "015",
                          "reserve",
                          "[quick][digraph]") {
    ActionDigraph<size_t> graph;
    graph.reserve(1010);
    REQUIRE(graph.number_of_nodes() == 0);
    REQUIRE(graph.number_of_edges() == 0);
    graph.add_nodes(1);
    REQUIRE(graph.number_of_nodes() == 1);
    graph.add_nodes(9);
    REQUIRE(graph.number_of_nodes() == 10);
    REQUIRE(graph.number_of_edges() == 0);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "016",
                          "default constructors",
                          "[quick][digraph]") {
    auto g1 = ActionDigraph<size_t>();
    g1.add_to_out_degree(1);
    action_digraph_helper::add_cycle(g1, 10);

    // Copy constructor
    auto g2(g1);
    REQUIRE(g2.number_of_edges() == 10);
    REQUIRE(g2.number_of_nodes() == 10);
    REQUIRE(g2.number_of_scc() == 1);

    // Move constructor
    auto g3(std::move(g2));
    REQUIRE(g3.number_of_edges() == 10);
    REQUIRE(g3.number_of_nodes() == 10);
    REQUIRE(g3.number_of_scc() == 1);

    // Copy assignment
    g2 = g3;
    REQUIRE(g2.number_of_edges() == 10);
    REQUIRE(g2.number_of_nodes() == 10);
    REQUIRE(g2.number_of_scc() == 1);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "017",
                          "scc iterators",
                          "[quick][digraph]") {
    using node_type = decltype(clique(1))::node_type;

    for (size_t n = 10; n < 512; n *= 4) {
      auto g = clique(n);
      REQUIRE(g.number_of_nodes() == n);
      REQUIRE(g.number_of_edges() == n * n);
      REQUIRE(g.number_of_scc() == 1);

      add_clique(g, n);

      REQUIRE(g.number_of_nodes() == 2 * n);
      REQUIRE(g.number_of_edges() == 2 * n * n);
      REQUIRE(g.number_of_scc() == 2);

      auto expected = std::vector<node_type>(n, 0);
      std::iota(expected.begin(), expected.end(), 0);
      auto result = std::vector<node_type>(g.cbegin_scc(0), g.cend_scc(0));
      std::sort(result.begin(), result.end());
      REQUIRE(result == expected);

      std::iota(expected.begin(), expected.end(), n);
      result.assign(g.cbegin_scc(1), g.cend_scc(1));
      std::sort(result.begin(), result.end());
      REQUIRE(result == expected);
      REQUIRE_THROWS_AS(g.cbegin_scc(2), LibsemigroupsException);
      REQUIRE_THROWS_AS(g.cend_scc(2), LibsemigroupsException);

      result.assign(g.cbegin_scc_roots(), g.cend_scc_roots());
      std::transform(result.begin(),
                     result.end(),
                     result.begin(),
                     [&g](node_type i) { return g.scc_id(i); });

      REQUIRE(result == std::vector<node_type>({01}));
    }
    {
      auto g = clique(10);
      for (size_t n = 0; n < 99; ++n) {
        add_clique(g, 10);
      }
      REQUIRE(g.number_of_nodes() == 1000);
      REQUIRE(g.number_of_edges() == 10000);
      REQUIRE(g.number_of_scc() == 100);

      auto result
          = std::vector<node_type>(g.cbegin_scc_roots(), g.cend_scc_roots());
      std::transform(result.begin(),
                     result.end(),
                     result.begin(),
                     [&g](node_type i) { return g.scc_id(i); });

      auto expected = std::vector<node_type>(1000);
      std::iota(expected.begin(), expected.end(), 0);

      REQUIRE(result == expected);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "018",
                          "iterator to edges",
                          "[quick][digraph]") {
    for (size_t n = 10; n < 512; n *= 4) {
      auto g = clique(n);
      REQUIRE(g.number_of_nodes() == n);
      REQUIRE(g.number_of_edges() == n * n);
      REQUIRE(g.number_of_scc() == 1);

      using node_type = decltype(g)::node_type;

      auto expected = std::vector<node_type>(n, 0);
      std::iota(expected.begin(), expected.end(), 0);

      for (auto it = g.cbegin_nodes(); it < g.cend_nodes(); ++it) {
        auto result
            = std::vector<node_type>(g.cbegin_edges(*it), g.cend_edges(*it));
        REQUIRE(result == expected);
      }
      REQUIRE_THROWS_AS(g.cbegin_edges(n), LibsemigroupsException);
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "019",
                          "root of scc",
                          "[quick][digraph]") {
    auto g = clique(10);
    for (size_t n = 0; n < 99; ++n) {
      add_clique(g, 10);
    }
    REQUIRE(g.number_of_nodes() == 1000);
    REQUIRE(g.number_of_edges() == 10000);
    REQUIRE(g.number_of_scc() == 100);

    using node_type = decltype(g)::node_type;

    for (auto it = g.cbegin_sccs(); it < g.cend_sccs(); ++it) {
      REQUIRE(std::all_of(it->cbegin(), it->cend(), [&g](node_type v) {
        return g.root_of_scc(v) == *g.cbegin_scc(g.scc_id(v));
      }));
    }
    REQUIRE_THROWS_AS(g.root_of_scc(1000), LibsemigroupsException);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "020",
                          "cbegin/end_panislo - 100 node path",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    using node_type = decltype(ad)::node_type;
    size_t const n  = 100;
    ad.add_nodes(n);
    ad.add_to_out_degree(2);
    for (size_t i = 0; i < n - 1; ++i) {
      ad.add_edge(i, i + 1, i % 2);
    }
    std::vector<std::pair<word_type, node_type>> pths(ad.cbegin_panilo(0),
                                                      ad.cend_panilo());
    REQUIRE(pths.size() == 100);
    REQUIRE(std::distance(ad.cbegin_panilo(50), ad.cend_panilo()) == 50);

    REQUIRE(ad.cbegin_panislo(0) != ad.cend_panislo());
    pths.clear();
    pths.insert(pths.end(), ad.cbegin_panislo(0), ad.cend_panislo());
    REQUIRE(pths.size() == 100);
    REQUIRE(pths[3].first == word_type({010}));
    REQUIRE(std::distance(ad.cbegin_panislo(50), ad.cend_panislo()) == 50);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "021",
                          "cbegin/end_pislo",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(9);
    ad.add_to_out_degree(3);
    ad.add_edge(010);
    ad.add_edge(021);
    ad.add_edge(230);
    ad.add_edge(241);
    ad.add_edge(451);

    ad.add_edge(262);
    ad.add_edge(671);
    ad.add_edge(780);

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(234), ad.cend_pislo())
            == std::vector<word_type>({{210}}));

    std::vector<word_type> expected;
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(000), ad.cend_pislo())
            == expected);

    expected.emplace_back(word_type());
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(001), ad.cend_pislo())
            == expected);

    expected.emplace_back(word_type({0}));
    expected.emplace_back(word_type({1}));
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(002), ad.cend_pislo())
            == expected);

    expected.emplace_back(word_type({10}));
    expected.emplace_back(word_type({11}));
    expected.emplace_back(word_type({12}));
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(003), ad.cend_pislo())
            == expected);

    expected.emplace_back(word_type({111}));
    expected.emplace_back(word_type({121}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(004), ad.cend_pislo())
            == expected);
    expected.emplace_back(word_type({1210}));
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(0010), ad.cend_pislo())
            == expected);

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(023), ad.cend_pislo())
            == std::vector<word_type>({{10}, {11}, {12}}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "022",
                          "cbegin/end_pani(s)lo - 100 node cycle",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_to_out_degree(1);
    action_digraph_helper::add_cycle(ad, 100);

    REQUIRE(std::distance(ad.cbegin_panilo(00200), ad.cend_panilo())
            == 200);
    REQUIRE(std::distance(ad.cbegin_panislo(00200), ad.cend_panislo())
            == 200);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "023",
                          "cbegin/cend_pilo - tree 14 nodes",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(15);
    ad.add_to_out_degree(2);

    ad.add_edge(010);
    ad.add_edge(021);

    ad.add_edge(130);
    ad.add_edge(141);

    ad.add_edge(250);
    ad.add_edge(261);

    ad.add_edge(370);
    ad.add_edge(381);

    ad.add_edge(490);
    ad.add_edge(4101);

    ad.add_edge(5110);
    ad.add_edge(5121);

    ad.add_edge(6130);
    ad.add_edge(6141);

    REQUIRE(std::vector<word_type>(ad.cbegin_pilo(003), ad.cend_pilo())
            == std::vector<word_type>(
                {{}, {0}, {00}, {01}, {1}, {10}, {11}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(003), ad.cend_pislo())
            == std::vector<word_type>(
                {{}, {0}, {1}, {00}, {01}, {10}, {11}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pilo(0), ad.cend_pilo())
            == std::vector<word_type>({{},
                                       {0},
                                       {00},
                                       {000},
                                       {001},
                                       {01},
                                       {010},
                                       {011},
                                       {1},
                                       {10},
                                       {100},
                                       {101},
                                       {11},
                                       {110},
                                       {111}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(0), ad.cend_pislo())
            == std::vector<word_type>({{},
                                       {0},
                                       {1},
                                       {00},
                                       {01},
                                       {10},
                                       {11},
                                       {000},
                                       {001},
                                       {010},
                                       {011},
                                       {100},
                                       {101},
                                       {110},
                                       {111}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pilo(01), ad.cend_pilo())
            == std::vector<word_type>({{0},
                                       {00},
                                       {000},
                                       {001},
                                       {01},
                                       {010},
                                       {011},
                                       {1},
                                       {10},
                                       {100},
                                       {101},
                                       {11},
                                       {110},
                                       {111}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(01), ad.cend_pislo())
            == std::vector<word_type>({{0},
                                       {1},
                                       {00},
                                       {01},
                                       {10},
                                       {11},
                                       {000},
                                       {001},
                                       {010},
                                       {011},
                                       {100},
                                       {101},
                                       {110},
                                       {111}}));
    REQUIRE(
        std::vector<word_type>(ad.cbegin_pilo(21), ad.cend_pilo())
        == std::vector<word_type>({{0}, {00}, {01}, {1}, {10}, {11}}));

    REQUIRE(
        std::vector<word_type>(ad.cbegin_pislo(21), ad.cend_pislo())
        == std::vector<word_type>({{0}, {1}, {00}, {01}, {10}, {11}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pilo(223), ad.cend_pilo())
            == std::vector<word_type>({{00}, {01}, {10}, {11}}));

    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(223), ad.cend_pislo())
            == std::vector<word_type>({{00}, {01}, {10}, {11}}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "024",
                          "cbegin/end_pstilo - Cayley digraph",
                          "[quick][no-valgrind]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(6);
    ad.add_to_out_degree(2);

    ad.add_edge(010);
    ad.add_edge(021);
    ad.add_edge(130);
    ad.add_edge(141);
    ad.add_edge(240);
    ad.add_edge(221);
    ad.add_edge(310);
    ad.add_edge(351);
    ad.add_edge(450);
    ad.add_edge(441);
    ad.add_edge(540);
    ad.add_edge(551);

    REQUIRE(ad.validate());
    REQUIRE(!action_digraph_helper::is_acyclic(ad));

    std::vector<word_type> expected = {{01},
                                       {10},
                                       {011},
                                       {110},
                                       {101},
                                       {1101},
                                       {1011},
                                       {1110},
                                       {0111},
                                       {1000},
                                       {0001},
                                       {0010},
                                       {0100}};

    std::sort(
        expected.begin(), expected.end(), LexicographicalCompare<word_type>());
    REQUIRE(
        std::vector<word_type>(ad.cbegin_pstilo(0405), ad.cend_pstilo())
        == expected);

    size_t const N = 18;

    expected.clear();
    for (auto it = cbegin_wilo(2, N, {}, word_type(N, 1));
         it != cend_wilo(2, N, {}, word_type(N, 1));
         ++it) {
      auto node = action_digraph_helper::follow_path(ad, 0, *it);
      if (node == 4) {
        expected.push_back(*it);
      }
    }
    REQUIRE(expected.size() == 131062);

    auto result = std::vector<word_type>(ad.cbegin_pstilo(040, N),
                                         ad.cend_pstilo());
    REQUIRE(result.size() == 131062);
    REQUIRE(result == expected);

    REQUIRE(ad.number_of_paths(040, N) == 131062);
    REQUIRE(ad.number_of_paths(0410, N) == 130556);
    REQUIRE(ad.number_of_paths(410, N) == 0);
    REQUIRE(ad.number_of_paths(00, POSITIVE_INFINITY) == POSITIVE_INFINITY);
    REQUIRE(ad.number_of_paths(0010) == 1023);

    auto it = ad.cend_pstilo();
    ++it;  // for code coverage
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "025",
                          "cbegin_pstilo - Tsalakou",
                          "[quick]") {
    using action_digraph_helper::follow_path;
    auto        rg = ReportGuard(false);
    KnuthBendix kb;
    kb.set_alphabet("ab");
    kb.add_rule("aaaaa""aa");
    kb.add_rule("bb""b");
    kb.add_rule("ab""b");

    REQUIRE(kb.size() == 9);
    auto S = static_cast<KnuthBendix::froidure_pin_type&>(*kb.froidure_pin());

    ActionDigraph<size_t> ad;
    ad.add_to_out_degree(S.number_of_generators());
    ad.add_nodes(S.size() + 1);

    for (size_t j = 0; j < S.number_of_generators(); ++j) {
      ad.add_edge(S.size(), j, j);
    }

    for (size_t i = 0; i < S.size(); ++i) {
      for (size_t j = 0; j < S.number_of_generators(); ++j) {
        ad.add_edge(i, S.right(i, j), j);
      }
    }

    std::vector<word_type> tprime;

    for (size_t i = 0; i < S.size(); ++i) {
      tprime.push_back(*ad.cbegin_pstilo(S.size(), i, 09));
    }
    REQUIRE(tprime.size() == 9);
    REQUIRE(tprime
            == std::vector<word_type>({{0},
                                       {00000001},
                                       {00},
                                       {00000010},
                                       {000},
                                       {00000100},
                                       {0000},
                                       {00001000},
                                       {00010000}}));

    std::vector<word_type> lprime;
    for (auto const& w : tprime) {
      for (size_t j = 0; j < S.number_of_generators(); ++j) {
        word_type ww(w);
        ww.push_back(j);
        if (std::find(tprime.cbegin(), tprime.cend(), ww) == tprime.cend()) {
          lprime.push_back(ww);
        }
      }
    }

    std::sort(
        lprime.begin(), lprime.end(), LexicographicalCompare<word_type>());

    REQUIRE(lprime.size() == 15);
    REQUIRE(lprime
            == std::vector<word_type>({{00000},
                                       {000000010},
                                       {000000011},
                                       {000000100},
                                       {000000101},
                                       {000001000},
                                       {000001001},
                                       {00001},
                                       {000010000},
                                       {000010001},
                                       {0001},
                                       {000100000},
                                       {000100001},
                                       {001},
                                       {01}}));
    std::vector<word_type> rhs(lprime.size(), word_type({}));
    for (size_t i = 0; i < lprime.size(); ++i) {
      rhs[i] = tprime[follow_path(ad, S.size(), lprime[i])];
    }

    REQUIRE(rhs
            == std::vector<word_type>({{00},
                                       {00000010},
                                       {00000001},
                                       {00000100},
                                       {00000001},
                                       {00001000},
                                       {00000001},
                                       {00000001},
                                       {00010000},
                                       {00000001},
                                       {00000001},
                                       {00000100},
                                       {00000001},
                                       {00000001},
                                       {00000001}}));
    for (size_t i = 0; i < lprime.size(); ++i) {
      REQUIRE(kb.equal_to(lprime[i], rhs[i]));
    }

    KnuthBendix kb2;
    kb2.set_alphabet(2);
    for (size_t i = 0; i < lprime.size(); ++i) {
      kb2.add_rule(lprime[i], rhs[i]);
    }
    kb2.add_rule({1}, {00000001});
    REQUIRE(kb2.size() == 9);
    kb2.froidure_pin()->run();
    REQUIRE(std::vector<relation_type>(kb2.froidure_pin()->cbegin_rules(),
                                       kb2.froidure_pin()->cend_rules())
            == std::vector<relation_type>(
                {{{01}, {1}}, {{11}, {1}}, {{00000}, {00}}}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "026",
                          "cbegin/end_pstislo - Cayley digraph",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(6);
    ad.add_to_out_degree(2);

    ad.add_edge(010);
    ad.add_edge(021);
    ad.add_edge(130);
    ad.add_edge(141);
    ad.add_edge(240);
    ad.add_edge(221);
    ad.add_edge(310);
    ad.add_edge(351);
    ad.add_edge(450);
    ad.add_edge(441);
    ad.add_edge(540);
    ad.add_edge(551);

    std::vector<word_type> expected = {{01},
                                       {10},
                                       {011},
                                       {110},
                                       {101},
                                       {1101},
                                       {1011},
                                       {1110},
                                       {0111},
                                       {1000},
                                       {0001},
                                       {0010},
                                       {0100}};

    std::sort(expected.begin(), expected.end(), ShortLexCompare<word_type>());
    REQUIRE(
        std::vector<word_type>(ad.cbegin_pstislo(0405), ad.cend_pstislo())
        == expected);

    size_t const N = 18;

    expected.clear();
    for (auto it = cbegin_wislo(2, {}, word_type(N, 0));
         it != cend_wislo(2, {}, word_type(N, 0));
         ++it) {
      auto node = action_digraph_helper::follow_path(ad, 0, *it);
      if (node == 4) {
        expected.push_back(*it);
      }
    }
    REQUIRE(expected.size() == 131062);

    auto result = std::vector<word_type>(ad.cbegin_pstislo(040, N),
                                         ad.cend_pstislo());
    REQUIRE(result.size() == 131062);
    REQUIRE(result == expected);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "027",
                          "cbegin/end_pstislo - Cayley digraph",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(6);
    ad.add_to_out_degree(3);

    ad.add_edge(010);
    ad.add_edge(021);
    ad.add_edge(120);
    ad.add_edge(101);
    ad.add_edge(132);
    ad.add_edge(232);
    ad.add_edge(340);
    ad.add_edge(451);
    ad.add_edge(530);

    REQUIRE(std::is_sorted(ad.cbegin_pislo(0010),
                           ad.cend_pislo(),
                           ShortLexCompare<word_type>()));
    REQUIRE(std::distance(ad.cbegin_pislo(0010), ad.cend_pislo()) == 75);
    REQUIRE(!action_digraph_helper::is_acyclic(ad));
    REQUIRE(ad.number_of_paths(0010) == 75);
    REQUIRE(ad.number_of_paths(00, POSITIVE_INFINITY) == POSITIVE_INFINITY);
    REQUIRE(std::vector<word_type>(ad.cbegin_pislo(0010), ad.cend_pislo())
            == std::vector<word_type>({{},
                                       {0},
                                       {1},
                                       {00},
                                       {01},
                                       {02},
                                       {12},
                                       {002},
                                       {010},
                                       {011},
                                       {020},
                                       {120},
                                       {0020},
                                       {0100},
                                       {0101},
                                       {0102},
                                       {0112},
                                       {0201},
                                       {1201},
                                       {00201},
                                       {01002},
                                       {01010},
                                       {01011},
                                       {01020},
                                       {01120},
                                       {02010},
                                       {12010},
                                       {002010},
                                       {010020},
                                       {010100},
                                       {010101},
                                       {010102},
                                       {010112},
                                       {010201},
                                       {011201},
                                       {020100},
                                       {120100},
                                       {0020100},
                                       {0100201},
                                       {0101002},
                                       {0101010},
                                       {0101011},
                                       {0101020},
                                       {0101120},
                                       {0102010},
                                       {0112010},
                                       {0201001},
                                       {1201001},
                                       {00201001},
                                       {01002010},
                                       {01010020},
                                       {01010100},
                                       {01010101},
                                       {01010102},
                                       {01010112},
                                       {01010201},
                                       {01011201},
                                       {01020100},
                                       {01120100},
                                       {02010010},
                                       {12010010},
                                       {002010010},
                                       {010020100},
                                       {010100201},
                                       {010101002},
                                       {010101010},
                                       {010101011},
                                       {010101020},
                                       {010101120},
                                       {010102010},
                                       {010112010},
                                       {010201001},
                                       {011201001},
                                       {020100100},
                                       {120100100}}));

    auto expected
        = std::vector<word_type>(ad.cbegin_pislo(0010), ad.cend_pislo());
    std::sort(
        expected.begin(), expected.end(), LexicographicalCompare<word_type>());
    REQUIRE(
        expected
        == std::vector<word_type>(ad.cbegin_pilo(0010), ad.cend_pilo()));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "028",
                          "path iterators corner cases",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(6);
    ad.add_to_out_degree(3);

    ad.add_edge(010);
    ad.add_edge(021);
    ad.add_edge(120);
    ad.add_edge(101);
    ad.add_edge(132);
    ad.add_edge(232);
    ad.add_edge(340);
    ad.add_edge(451);
    ad.add_edge(530);
    REQUIRE_THROWS_AS(ad.cbegin_pstilo(16), LibsemigroupsException);
    REQUIRE_THROWS_AS(ad.cbegin_pstilo(61), LibsemigroupsException);
    REQUIRE(ad.cbegin_pstilo(21) == ad.cend_pstilo());
    REQUIRE(ad.cbegin_pstilo(03101) == ad.cend_pstilo());

    REQUIRE_THROWS_AS(ad.cbegin_pstislo(16), LibsemigroupsException);
    REQUIRE_THROWS_AS(ad.cbegin_pstislo(61), LibsemigroupsException);
    REQUIRE(ad.cbegin_pstislo(21) == ad.cend_pstislo());
    REQUIRE(ad.cbegin_pstislo(03101) == ad.cend_pstislo());

    REQUIRE_THROWS_AS(ad.cbegin_panilo(6), LibsemigroupsException);
    REQUIRE(ad.cbegin_panilo(011) == ad.cend_panilo());
    REQUIRE_THROWS_AS(ad.cbegin_panislo(6), LibsemigroupsException);
    REQUIRE(ad.cbegin_panislo(011) == ad.cend_panislo());

    REQUIRE_THROWS_AS(ad.cbegin_pilo(6), LibsemigroupsException);
    REQUIRE(ad.cbegin_pilo(011) == ad.cend_pilo());

    REQUIRE_THROWS_AS(ad.cbegin_pislo(6), LibsemigroupsException);
    REQUIRE(ad.cbegin_pislo(011) == ad.cend_pislo());

    verify_forward_iterator_requirements(ad.cbegin_panilo(0));
    verify_forward_iterator_requirements(ad.cbegin_panislo(0));
    verify_forward_iterator_requirements(ad.cbegin_pilo(0));
    verify_forward_iterator_requirements(ad.cbegin_pislo(0));
    verify_forward_iterator_requirements(ad.cbegin_pstilo(01));
    verify_forward_iterator_requirements(ad.cbegin_pstislo(01));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "029",
                          "reverse node iterator",
                          "[quick]") {
    using node_type = ActionDigraph<size_t>::node_type;
    ActionDigraph<size_t> ad;
    ad.add_nodes(10);
    REQUIRE(ad.number_of_nodes() == 10);
    REQUIRE(std::vector<node_type>(ad.cbegin_nodes(), ad.cend_nodes())
            == std::vector<node_type>({0123456789}));

    auto it = ad.cbegin_nodes();
    REQUIRE(*it == 0);
    auto copy(it);
    REQUIRE(*copy == 0);
    it       = ad.cend_nodes();
    auto tmp = it;
    REQUIRE(*--tmp == 9);

    REQUIRE(std::vector<node_type>(ad.crbegin_nodes(), ad.crend_nodes())
            == std::vector<node_type>({9876543210}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "030",
                          "pstilo corner case",
                          "[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(5);
    ad.add_to_out_degree(2);
    ad.add_edge(011);
    ad.add_edge(020);
    ad.add_edge(230);
    ad.add_edge(340);
    ad.add_edge(420);
    // Tests the case then there is only a single path, but if we would have
    // used panilo (i.e. not use the reachability check that is in pstilo),
    // then we'd enter an infinite loop.

    auto it = ad.cbegin_pstilo(01);
    REQUIRE(*it == word_type({1}));
    ++it;
    REQUIRE(it == ad.cend_pstilo());

    ad = chain(5);
    REQUIRE(std::distance(ad.cbegin_pstilo(000100), ad.cend_pstilo())
            == 1);
    REQUIRE(std::distance(ad.cbegin_pstilo(004100), ad.cend_pstilo())
            == 0);

    ad = ActionDigraph<size_t>();
    ad.add_to_out_degree(1);
    action_digraph_helper::add_cycle(ad, 5);
    REQUIRE(std::distance(ad.cbegin_pstilo(0006), ad.cend_pstilo()) == 2);
    REQUIRE(std::distance(ad.cbegin_pstilo(000100), ad.cend_pstilo())
            == 20);
    REQUIRE(std::distance(ad.cbegin_pstilo(004100), ad.cend_pstilo())
            == 19);

    // There's 1 path from 0 to 0 of length in range [0, 1), the path of length
    // 0.
    REQUIRE(std::distance(ad.cbegin_pstilo(0002), ad.cend_pstilo()) == 1);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "031",
                          "number_of_paths corner cases",
                          "[quick]") {
    using algorithm = ActionDigraph<size_t>::algorithm;
    ActionDigraph<size_t> ad;
    REQUIRE_THROWS_AS(ad.number_of_paths(00, POSITIVE_INFINITY),
                      LibsemigroupsException);
    size_t const n = 20;
    ad.add_to_out_degree(1);
    action_digraph_helper::add_cycle(ad, n);
    REQUIRE(ad.number_of_paths(10) == POSITIVE_INFINITY);
    REQUIRE(ad.number_of_paths_algorithm(10100, POSITIVE_INFINITY)
            == algorithm::trivial);
    REQUIRE(ad.number_of_paths(10100, POSITIVE_INFINITY)
            == POSITIVE_INFINITY);
    ad = chain(n);
    REQUIRE(ad.number_of_paths(10) == 10);
    REQUIRE(ad.number_of_paths(19) == 1);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "032",
                          "number_of_paths acyclic digraph",
                          "[quick]") {
    using node_type = ActionDigraph<size_t>::node_type;
    ActionDigraph<size_t> ad;
    ad.add_nodes(8);
    ad.add_to_out_degree(3);
    ad.add_edge(030);
    ad.add_edge(021);
    ad.add_edge(032);
    ad.add_edge(170);
    ad.add_edge(210);
    ad.add_edge(310);
    ad.add_edge(351);
    ad.add_edge(460);
    ad.add_edge(630);
    ad.add_edge(671);

    REQUIRE(action_digraph_helper::is_acyclic(ad));

    size_t expected[8][8][8] = {{{014912121212},
                                 {003811111111},
                                 {00058888},
                                 {00003333},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01222222},
                                 {00111111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01233333},
                                 {00122222},
                                 {00011111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01344444},
                                 {00233333},
                                 {00011111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01246777},
                                 {00135666},
                                 {00024555},
                                 {00002333},
                                 {00000111},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01111111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01356666},
                                 {00245555},
                                 {00023333},
                                 {00001111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}},
                                {{01111111},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000},
                                 {00000000}}};
    for (auto s = ad.cbegin_nodes(); s != ad.cend_nodes(); ++s) {
      for (size_t min = 0; min < ad.number_of_nodes(); ++min) {
        for (size_t max = 0; max < ad.number_of_nodes(); ++max) {
          REQUIRE(size_t(std::distance(ad.cbegin_pilo(*s, min, max),
                                       ad.cend_pilo()))
                  == expected[*s][min][max]);
        }
      }
    }

    for (auto s = ad.cbegin_nodes(); s != ad.cend_nodes(); ++s) {
      for (size_t min = 0; min < ad.number_of_nodes(); ++min) {
        for (size_t max = 0; max < ad.number_of_nodes(); ++max) {
          REQUIRE(ad.number_of_paths(*s, min, max) == expected[*s][min][max]);
        }
      }
    }

    size_t const N = ad.number_of_nodes();
    REQUIRE(
        std::vector<word_type>(ad.cbegin_pstilo(0302), ad.cend_pstilo())
        == std::vector<word_type>({{0}, {2}}));
    using algorithm = ActionDigraph<size_t>::algorithm;
    REQUIRE(ad.number_of_paths(0302, algorithm::acyclic)
            == size_t(
                std::distance(ad.cbegin_pstilo(0302), ad.cend_pstilo())));

    for (auto s = ad.cbegin_nodes(); s != ad.cend_nodes(); ++s) {
      for (auto t = ad.cbegin_nodes(); t != ad.cend_nodes(); ++t) {
        for (node_type min = 0; min < N; ++min) {
          for (size_t max = min; max < N; ++max) {
            REQUIRE(ad.number_of_paths(*s, *t, min, max)
                    == size_t(std::distance(ad.cbegin_pstilo(*s, *t, min, max),
                                            ad.cend_pstilo())));
          }
        }
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "033",
                          "number_of_paths binary tree",
                          "[quick][no-valgrind]") {
    using algorithm          = ActionDigraph<size_t>::algorithm;
    using node_type          = ActionDigraph<size_t>::node_type;
    size_t const          n  = 6;
    ActionDigraph<size_t> ad = binary_tree(n);
    REQUIRE(ad.number_of_nodes() == std::pow(2, n) - 1);
    REQUIRE(ad.number_of_edges() == std::pow(2, n) - 2);
    REQUIRE(action_digraph_helper::is_acyclic(ad));
    REQUIRE(ad.number_of_paths(0) == std::pow(2, n) - 1);

    for (auto s = ad.cbegin_nodes(); s != ad.cend_nodes(); ++s) {
      for (node_type min = 0; min < n; ++min) {
        for (size_t max = min; max < n; ++max) {
          REQUIRE(ad.number_of_paths(*s, min, max)
                  == size_t(std::distance(ad.cbegin_pilo(*s, min, max),
                                          ad.cend_pilo())));
        }
      }
    }
    REQUIRE(ad.number_of_paths_algorithm(0101) == algorithm::acyclic);

    REQUIRE(ad.number_of_paths(0101)
            == size_t(
                std::distance(ad.cbegin_pstilo(0101), ad.cend_pstilo())));

    for (auto s = ad.cbegin_nodes(); s != ad.cend_nodes(); ++s) {
      for (auto t = ad.cbegin_nodes(); t != ad.cend_nodes(); ++t) {
        for (node_type min = 0; min < n; ++min) {
          for (size_t max = min; max < n; ++max) {
            REQUIRE(ad.number_of_paths(*s, *t, min, max)
                    == size_t(std::distance(ad.cbegin_pstilo(*s, *t, min, max),
                                            ad.cend_pstilo())));
          }
        }
      }
    }
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "034",
                          "number_of_paths large binary tree",
                          "[quick][no-valgrind]") {
    using algorithm          = ActionDigraph<size_t>::algorithm;
    size_t const          n  = 20;
    ActionDigraph<size_t> ad = binary_tree(n);
    REQUIRE(ad.number_of_nodes() == std::pow(2, n) - 1);
    REQUIRE(ad.number_of_edges() == std::pow(2, n) - 2);
    REQUIRE(action_digraph_helper::is_acyclic(ad));
    REQUIRE(ad.number_of_paths_algorithm(0) == algorithm::acyclic);
    REQUIRE(ad.number_of_paths(0) == std::pow(2, n) - 1);

    // The following tests for code coverage
    ad.add_edge(1900);
    REQUIRE(
        ad.number_of_paths(
            000, POSITIVE_INFINITY, ActionDigraph<size_t>::algorithm::dfs)
        == POSITIVE_INFINITY);
    // 0 not reachable from 10
    REQUIRE(ad.number_of_paths(10,
                               0,
                               0,
                               POSITIVE_INFINITY,
                               ActionDigraph<size_t>::algorithm::matrix)
            == 0);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "035",
                          "number_of_paths 400 node random digraph",
                          "[quick]") {
    size_t const n  = 400;
    auto         ad = ActionDigraph<size_t>::random(n, 20, n, std::mt19937());
    action_digraph_helper::add_cycle(ad, ad.cbegin_nodes(), ad.cend_nodes());
    REQUIRE(!action_digraph_helper::is_acyclic(ad));
    REQUIRE(!ad.validate());
    REQUIRE(ad.number_of_paths_algorithm(0016)
            == ActionDigraph<size_t>::algorithm::dfs);
    REQUIRE(ad.number_of_paths(0016) != 0);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "036",
                          "number_of_paths 10 node acyclic digraph",
                          "[quick]") {
    using algorithm = ActionDigraph<size_t>::algorithm;
    // size_t const n  = 10;
    // auto ad = ActionDigraph<size_t>::random_acyclic(n, 20, n,
    // std::mt19937()); std::cout <<
    // action_digraph_helper::detail::to_string(ad);
    ActionDigraph<size_t> ad;
    ad.add_nodes(10);
    ad.add_to_out_degree(20);
    ad.add_edge(075);
    ad.add_edge(057);
    ad.add_edge(1914);
    ad.add_edge(1517);
    ad.add_edge(385);
    ad.add_edge(581);
    ad.add_edge(6814);
    ad.add_edge(7810);
    ad.add_edge(8912);
    ad.add_edge(8913);
    REQUIRE(action_digraph_helper::is_acyclic(ad));
    REQUIRE(!ad.validate());

    REQUIRE(ad.number_of_paths_algorithm(0016) == algorithm::acyclic);
    REQUIRE(ad.number_of_paths(0030) == 9);
    REQUIRE(ad.number_of_paths(1010, algorithm::acyclic) == 6);
    REQUIRE(ad.number_of_paths(1010, algorithm::matrix) == 6);
    REQUIRE(ad.number_of_paths(19010, algorithm::matrix) == 3);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "037",
                          "number_of_paths node digraph",
                          "[quick]") {
    using algorithm = ActionDigraph<size_t>::algorithm;
    size_t const n  = 10;
    // auto         ad = ActionDigraph<size_t>::random(n, 20, 200,
    // std::mt19937()); std::cout <<
    // action_digraph_helper::detail::to_string(ad);
    ActionDigraph<size_t> ad;
    ad.add_nodes(10);
    ad.add_to_out_degree(20);
    ad.add_edge(090);
    ad.add_edge(011);
    ad.add_edge(062);
    ad.add_edge(033);
    ad.add_edge(074);
    ad.add_edge(025);
    ad.add_edge(026);
    ad.add_edge(087);
    ad.add_edge(018);
    ad.add_edge(049);
    ad.add_edge(0310);
    ad.add_edge(0111);
    ad.add_edge(0712);
    ad.add_edge(0913);
    ad.add_edge(0414);
    ad.add_edge(0715);
    ad.add_edge(0816);
    ad.add_edge(0917);
    ad.add_edge(0618);
    ad.add_edge(0919);
    ad.add_edge(180);
    ad.add_edge(121);
    ad.add_edge(152);
    ad.add_edge(173);
    ad.add_edge(194);
    ad.add_edge(105);
    ad.add_edge(126);
    ad.add_edge(147);
    ad.add_edge(108);
    ad.add_edge(139);
    ad.add_edge(1210);
    ad.add_edge(1711);
    ad.add_edge(1212);
    ad.add_edge(1713);
    ad.add_edge(1614);
    ad.add_edge(1615);
    ad.add_edge(1516);
    ad.add_edge(1417);
    ad.add_edge(1618);
    ad.add_edge(1319);
    ad.add_edge(220);
    ad.add_edge(291);
    ad.add_edge(202);
    ad.add_edge(263);
    ad.add_edge(274);
    ad.add_edge(295);
    ad.add_edge(256);
    ad.add_edge(247);
    ad.add_edge(298);
    ad.add_edge(279);
    ad.add_edge(2910);
    ad.add_edge(2911);
    ad.add_edge(2012);
    ad.add_edge(2713);
    ad.add_edge(2914);
    ad.add_edge(2615);
    ad.add_edge(2316);
    ad.add_edge(2317);
    ad.add_edge(2418);
    ad.add_edge(2119);
    ad.add_edge(310);
    ad.add_edge(391);
    ad.add_edge(362);
    ad.add_edge(323);
    ad.add_edge(394);
    ad.add_edge(385);
    ad.add_edge(316);
    ad.add_edge(367);
    ad.add_edge(318);
    ad.add_edge(309);
    ad.add_edge(3510);
    ad.add_edge(3011);
    ad.add_edge(3212);
    ad.add_edge(3713);
    ad.add_edge(3414);
    ad.add_edge(3015);
    ad.add_edge(3416);
    ad.add_edge(3817);
    ad.add_edge(3318);
    ad.add_edge(3119);
    ad.add_edge(400);
    ad.add_edge(441);
    ad.add_edge(482);
    ad.add_edge(453);
    ad.add_edge(454);
    ad.add_edge(415);
    ad.add_edge(436);
    ad.add_edge(487);
    ad.add_edge(448);
    ad.add_edge(449);
    ad.add_edge(4410);
    ad.add_edge(4711);
    ad.add_edge(4812);
    ad.add_edge(4613);
    ad.add_edge(4314);
    ad.add_edge(4715);
    ad.add_edge(4616);
    ad.add_edge(4717);
    ad.add_edge(4018);
    ad.add_edge(4219);
    ad.add_edge(530);
    ad.add_edge(501);
    ad.add_edge(542);
    ad.add_edge(573);
    ad.add_edge(524);
    ad.add_edge(555);
    ad.add_edge(576);
    ad.add_edge(577);
    ad.add_edge(578);
    ad.add_edge(579);
    ad.add_edge(5010);
    ad.add_edge(5811);
    ad.add_edge(5612);
    ad.add_edge(5813);
    ad.add_edge(5814);
    ad.add_edge(5115);
    ad.add_edge(5516);
    ad.add_edge(5517);
    ad.add_edge(5318);
    ad.add_edge(5719);
    ad.add_edge(680);
    ad.add_edge(671);
    ad.add_edge(662);
    ad.add_edge(653);
    ad.add_edge(664);
    ad.add_edge(615);
    ad.add_edge(676);
    ad.add_edge(627);
    ad.add_edge(678);
    ad.add_edge(639);
    ad.add_edge(6310);
    ad.add_edge(6811);
    ad.add_edge(6312);
    ad.add_edge(6913);
    ad.add_edge(6414);
    ad.add_edge(6115);
    ad.add_edge(6416);
    ad.add_edge(6317);
    ad.add_edge(6918);
    ad.add_edge(6819);
    ad.add_edge(790);
    ad.add_edge(741);
    ad.add_edge(732);
    ad.add_edge(783);
    ad.add_edge(704);
    ad.add_edge(755);
    ad.add_edge(766);
    ad.add_edge(787);
    ad.add_edge(798);
    ad.add_edge(719);
    ad.add_edge(7710);
    ad.add_edge(7011);
    ad.add_edge(7612);
    ad.add_edge(7213);
    ad.add_edge(7314);
    ad.add_edge(7815);
    ad.add_edge(7616);
    ad.add_edge(7317);
    ad.add_edge(7218);
    ad.add_edge(7719);
    ad.add_edge(800);
    ad.add_edge(861);
    ad.add_edge(832);
    ad.add_edge(853);
    ad.add_edge(874);
    ad.add_edge(895);
    ad.add_edge(896);
    ad.add_edge(887);
    ad.add_edge(818);
    ad.add_edge(859);
    ad.add_edge(8710);
    ad.add_edge(8911);
    ad.add_edge(8612);
    ad.add_edge(8013);
    ad.add_edge(8014);
    ad.add_edge(8315);
    ad.add_edge(8616);
    ad.add_edge(8017);
    ad.add_edge(8818);
    ad.add_edge(8919);
    ad.add_edge(930);
    ad.add_edge(971);
    ad.add_edge(992);
    ad.add_edge(913);
    ad.add_edge(944);
    ad.add_edge(995);
    ad.add_edge(946);
    ad.add_edge(907);
    ad.add_edge(958);
    ad.add_edge(989);
    ad.add_edge(9310);
    ad.add_edge(9211);
    ad.add_edge(9012);
    ad.add_edge(9213);
    ad.add_edge(9314);
    ad.add_edge(9415);
    ad.add_edge(9016);
    ad.add_edge(9517);
    ad.add_edge(9318);
    ad.add_edge(9519);
    REQUIRE(!action_digraph_helper::is_acyclic(ad));
    REQUIRE(ad.validate());

    REQUIRE(ad.number_of_paths_algorithm(0) == algorithm::acyclic);
    REQUIRE(ad.number_of_paths(0) == POSITIVE_INFINITY);
    REQUIRE_THROWS_AS(ad.number_of_paths(0010, algorithm::acyclic),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(ad.number_of_paths(19010, algorithm::acyclic),
                      LibsemigroupsException);

    ad = binary_tree(n);
    REQUIRE(ad.number_of_paths_algorithm(0) == algorithm::acyclic);
    REQUIRE(ad.number_of_paths(0) == 1023);

    action_digraph_helper::add_cycle(ad, n);
    ad.add_edge(0, n + 10);
    REQUIRE(!action_digraph_helper::is_acyclic(ad));
    REQUIRE(!ad.validate());
    REQUIRE(ad.number_of_paths(1) == 511);
    REQUIRE(ad.number_of_paths_algorithm(10, POSITIVE_INFINITY)
            == algorithm::acyclic);
    REQUIRE(ad.number_of_paths(10, POSITIVE_INFINITY) == 511);
    REQUIRE(action_digraph_helper::topological_sort(ad).empty());
    REQUIRE(*std::find_if(ad.cbegin_nodes(), ad.cend_nodes(), [&ad](size_t m) {
      return action_digraph_helper::topological_sort(ad, m).empty();
    }) == 1023);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "038",
                          "random/random_acyclic exceptions",
                          "[quick]") {
    // Too few nodes
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random(000),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random_acyclic(000),
                      LibsemigroupsException);
    // Out degree too low
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random(200),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random_acyclic(200),
                      LibsemigroupsException);
    // Number of edges too high
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random(225),
                      LibsemigroupsException);
    REQUIRE_THROWS_AS(ActionDigraph<size_t>::random_acyclic(225),
                      LibsemigroupsException);
    // Number of edges = 0
    auto ad = ActionDigraph<size_t>::random(220);
    REQUIRE(ad.number_of_edges() == 0);
    ad = ActionDigraph<size_t>::random_acyclic(220);
    REQUIRE(ad.number_of_edges() == 0);
    ad = ActionDigraph<size_t>::random_acyclic(101041);
    REQUIRE(ad.number_of_edges() == 41);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "039",
                          "unsafe (next) neighbour",
                          "[quick]") {
    auto ad = binary_tree(10);
    REQUIRE(ad.unsafe_neighbor(01) == ad.neighbor(01));
    REQUIRE(ad.unsafe_next_neighbor(01) == ad.next_neighbor(01));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "040",
                          "number_of_egdes incident to a node",
                          "[quick]") {
    auto ad = binary_tree(10);
    REQUIRE(ad.number_of_nodes() == 1023);
    REQUIRE(
        std::count_if(ad.cbegin_nodes(),
                      ad.cend_nodes(),
                      [&ad](size_t n) { return ad.number_of_edges(n) == 2; })
        == 511);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "041",
                          "number_of_paths (matrix)",
                          "[quick]") {
    using algorithm = ActionDigraph<size_t>::algorithm;
    // REQUIRE(detail::magic_number(6) * 6 == 14.634);
    // auto ad = ActionDigraph<size_t>::random(6, 3, 15, std::mt19937());
    // std::cout << action_digraph_helper::detail::to_string(ad);
    ActionDigraph<size_t> ad;
    ad.add_nodes(6);
    ad.add_to_out_degree(3);
    ad.add_edge(000);
    ad.add_edge(031);
    ad.add_edge(042);
    ad.add_edge(120);
    ad.add_edge(111);
    ad.add_edge(142);
    ad.add_edge(240);
    ad.add_edge(231);
    ad.add_edge(242);
    ad.add_edge(300);
    ad.add_edge(311);
    ad.add_edge(431);
    ad.add_edge(432);
    ad.add_edge(540);
    ad.add_edge(522);

    REQUIRE(ad.number_of_edges() == 15);
    REQUIRE(std::distance(ad.cbegin_pilo(0010), ad.cend_pilo()) == 6858);
    REQUIRE(ad.number_of_paths_algorithm(0010) == algorithm::matrix);
    REQUIRE(ad.number_of_paths(0010) == 6858);
    REQUIRE_THROWS_AS(ad.number_of_paths(1010, algorithm::trivial),
                      LibsemigroupsException);
    REQUIRE(ad.number_of_paths_algorithm(01012) == algorithm::matrix);
    REQUIRE(ad.number_of_paths(01012) == 35300);

    auto checker1 = [&ad](word_type const& w) {
      return 10 <= w.size() && w.size() < 12
             && action_digraph_helper::follow_path(ad, 0, w) != UNDEFINED;
    };
    REQUIRE(std::all_of(ad.cbegin_pilo(01012), ad.cend_pilo(), checker1));
    REQUIRE(
        std::unordered_set<word_type>(ad.cbegin_pilo(01012), ad.cend_pilo())
            .size()
        == 35300);

    REQUIRE(std::distance(ad.cbegin_pilo(01012), ad.cend_pilo()) == 35300);

    REQUIRE(ad.number_of_paths_algorithm(15010) == algorithm::trivial);
    REQUIRE(ad.number_of_paths(15010) == 0);
    REQUIRE(0
            == std::distance(ad.cbegin_pstilo(15010), ad.cend_pstilo()));
    REQUIRE(ad.number_of_paths(11010) == 1404);
    REQUIRE_THROWS_AS(ad.number_of_paths(11010, algorithm::trivial),
                      LibsemigroupsException);
    REQUIRE(ad.number_of_paths(11010)
            == uint64_t(std::distance(ad.cbegin_pstilo(11010),
                                      ad.cend_pstilo())));

    auto checker2 = [&ad](word_type const& w) {
      return w.size() < 10 && action_digraph_helper::follow_path(ad, 1, w) == 1;
    };
    REQUIRE(
        std::all_of(ad.cbegin_pstilo(11010), ad.cend_pstilo(), checker2));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "042",
                          "number_of_paths (matrix)",
                          "[quick]") {
    using algorithm = ActionDigraph<size_t>::algorithm;
    ActionDigraph<size_t> ad;
    ad.add_nodes(2);
    ad.add_to_out_degree(2);
    ad.add_edge(010);
    ad.add_edge(100);

    REQUIRE(ad.number_of_paths(010, POSITIVE_INFINITY, algorithm::matrix)
            == POSITIVE_INFINITY);
    REQUIRE(ad.number_of_paths(01010, algorithm::matrix) == 5);
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph""011""restrict""[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(3);
    ad.add_to_out_degree(2);
    ad.add_edge(010);
    ad.add_edge(100);
    ad.add_edge(200);

    ad.restrict(2);
    REQUIRE(ad
            == action_digraph_helper::make<size_t>(2, {{1, UNDEFINED}, {0}}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph""012""remove_edge_nc""[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(3);
    ad.add_to_out_degree(2);
    ad.add_edge(010);
    ad.add_edge(100);
    ad.add_edge(200);

    ad.remove_edge_nc(00);  // remove edge from 0 labelled 0
    REQUIRE(ad
            == action_digraph_helper::make<size_t>(
                3, {{UNDEFINED, UNDEFINED}, {0}, {0}}));
  }

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph""043""swap_edge_nc""[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(3);
    ad.add_to_out_degree(2);
    ad.add_edge(010);
    ad.add_edge(100);
    ad.add_edge(220);

    // swap edge from 0 labelled 0 with edge from 1 labelled 0
    ad.swap_edges_nc(010);
    REQUIRE(
        ad
        == action_digraph_helper::make<size_t>(3, {{0, UNDEFINED}, {1}, {2}}));
  }

#ifdef LIBSEMIGROUPS_EIGEN_ENABLED
  LIBSEMIGROUPS_TEST_CASE("ActionDigraph",
                          "044",
                          "detail::pow for non-square Eigen matrix",
                          "[quick]") {
    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> x;
    x.resize(32);
    REQUIRE_THROWS_AS(detail::pow(x, 2), LibsemigroupsException);
  }
#endif

  LIBSEMIGROUPS_TEST_CASE("ActionDigraph""045""operator<<""[quick]") {
    ActionDigraph<size_t> ad;
    ad.add_nodes(3);
    ad.add_to_out_degree(2);
    ad.add_edge(010);
    ad.add_edge(100);
    ad.add_edge(220);

    std::ostringstream oss;
    oss << ad;
    REQUIRE(oss.str() == "{{1, -}, {0, -}, {2, -}}");
  }
}  // namespace libsemigroups

Messung V0.5 in Prozent
C=72 H=89 G=80

¤ Dauer der Verarbeitung: 0.46 Sekunden  (vorverarbeitet am  2026-06-17) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.