Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  test-matrix.cpp   Sprache: C

 
// libsemigroups - C++ library for semigroups and monoids
// Copyright (C) 2020 James D. Mitchell
//
// 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/>.

#include <algorithm>    // for lexicographical_compare
#include <array>        // for array
#include <cstddef>      // for size_t
#include <numeric>      // for accumulate
#include <type_traits>  // for move, swap, dec...
#include <utility>      // for operator==, pair
#include <vector>       // for vector

#define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER

#include "catch.hpp"      // for REQUIRE, REQUIRE_THROWS_AS, REQUIRE_NOTHROW
#include "test-main.hpp"  // for LIBSEMIGROUPS_TEST_CASE

#include "libsemigroups/adapters.hpp"      // for Complexity, Degree
#include "libsemigroups/bmat8.hpp"         // for BMat8
#include "libsemigroups/constants.hpp"     // for NEGATIVE_INFINITY
#include "libsemigroups/containers.hpp"    // for StaticVector1
#include "libsemigroups/debug.hpp"         // for LIBSEMIGROUPS_A...
#include "libsemigroups/exception.hpp"     // for LibsemigroupsEx...
#include "libsemigroups/fastest-bmat.hpp"  // for FastestBMat
#include "libsemigroups/matrix.hpp"        // for BMat, NTPMat
#include "libsemigroups/report.hpp"        // for ReportGuard

namespace libsemigroups {
  template <size_t N>
  class BitSet;

  constexpr bool REPORT = false;

  namespace {

    ////////////////////////////////////////////////////////////////////////
    // For comparison
    ////////////////////////////////////////////////////////////////////////

    template <typename Plus, typename Container>
    struct RowAddition {
      void operator()(Container& x, Container const& y) const {
        LIBSEMIGROUPS_ASSERT(x.size() == y.size());
        for (size_t i = 0; i < x.size(); ++i) {
          x[i] = Plus()(x[i], y[i]);
        }
      }

      void operator()(Container&       res,
                      Container const& x,
                      Container const& y) const {
        LIBSEMIGROUPS_ASSERT(res.size() == x.size());
        LIBSEMIGROUPS_ASSERT(x.size() == y.size());
        for (size_t i = 0; i < x.size(); ++i) {
          res[i] = Plus()(x[i], y[i]);
        }
      }
    };

    template <typename Prod, typename Container>
    Container scalar_row_product(Container                      row,
                                 typename Container::value_type scalar) {
      Container out(row);
      for (size_t i = 0; i < out.size(); ++i) {
        out[i] = Prod()(out[i], scalar);
      }
      return out;
    }

    template <size_t dim, size_t thresh>
    void tropical_max_plus_row_basis(std::vector<std::array<int, dim>>& rows) {
      static thread_local std::vector<std::array<int, dim>> buf;
      buf.clear();
      std::sort(rows.begin(), rows.end());
      for (size_t row = 0; row < rows.size(); ++row) {
        std::array<int, dim> sum;
        sum.fill(NEGATIVE_INFINITY);
        if (row == 0 || rows[row] != rows[row - 1]) {
          for (size_t row2 = 0; row2 < row; ++row2) {
            int max_scalar = thresh;
            for (size_t col = 0; col < dim; ++col) {
              if (rows[row2][col] == NEGATIVE_INFINITY) {
                continue;
              }
              if (rows[row][col] >= rows[row2][col]) {
                if (rows[row][col] != thresh) {
                  max_scalar
                      = std::min(max_scalar, rows[row][col] - rows[row2][col]);
                }
              } else {
                max_scalar = NEGATIVE_INFINITY;
                break;
              }
            }
            if (max_scalar != NEGATIVE_INFINITY) {
              auto scalar_prod
                  = scalar_row_product<MaxPlusTruncProd<thresh, int>,
                                       std::array<int, dim>>(rows[row2],
                                                             max_scalar);
              RowAddition<MaxPlusPlus<int>, std::array<int, dim>>()(
                  sum, scalar_prod);
            }
          }
          if (sum != rows[row]) {
            buf.push_back(rows[row]);
          }
        }
      }
      std::swap(buf, rows);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - BMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_BMat000() {
      auto rg = ReportGuard(REPORT);
      {
        Mat m = Mat::make({{0, 1}, {0, 1}});
        REQUIRE_NOTHROW(validate(m));
        REQUIRE(m == Mat({{0, 1}, {0, 1}}));
        REQUIRE(!(m == Mat({{0, 0}, {0, 1}})));
        REQUIRE(m == Mat({{0, 1}, {0, 1}}));
        m.product_inplace(Mat({{0, 0}, {0, 0}}), Mat({{0, 0}, {0, 0}}));
        REQUIRE(m == Mat({{0, 0}, {0, 0}}));
        m.product_inplace(Mat({{0, 0}, {0, 0}}), Mat({{1, 1}, {1, 1}}));
        REQUIRE(m == Mat({{0, 0}, {0, 0}}));
        m.product_inplace(Mat({{1, 1}, {1, 1}}), Mat({{0, 0}, {0, 0}}));
        REQUIRE(m == Mat({{0, 0}, {0, 0}}));

        m.product_inplace(Mat({{0, 1}, {1, 0}}), Mat({{1, 0}, {1, 0}}));
        REQUIRE(m == Mat({{1, 0}, {1, 0}}));
        size_t const M = detail::BitSetCapacity<Mat>::value;
        detail::StaticVector1<BitSet<M>, M> result;
        matrix_helpers::bitset_rows(m, result);
        REQUIRE(result.size() == 2);
        REQUIRE(matrix_helpers::bitset_rows(m).size() == 2);
        result.clear();
        matrix_helpers::bitset_row_basis(m, result);
        REQUIRE(result.size() == 1);
        REQUIRE(matrix_helpers::bitset_row_basis(m).size() == 1);
      }

      {
        Mat m({{1, 1}, {0, 0}});
        using RowView = typename Mat::RowView;
        auto r        = matrix_helpers::rows(m);
        REQUIRE(std::vector<bool>(r[0].cbegin(), r[0].cend())
                == std::vector<bool>({truetrue}));
        REQUIRE(std::vector<bool>(r[1].cbegin(), r[1].cend())
                == std::vector<bool>({falsefalse}));
        REQUIRE(r.size() == 2);
        std::sort(
            r.begin(), r.end(), [](RowView const& rv1, RowView const& rv2) {
              return std::lexicographical_compare(
                  rv1.begin(), rv1.end(), rv2.begin(), rv2.end());
            });
        REQUIRE(std::vector<bool>(r[0].cbegin(), r[0].cend())
                == std::vector<bool>({falsefalse}));
        REQUIRE(std::vector<bool>(r[1].cbegin(), r[1].cend())
                == std::vector<bool>({truetrue}));
      }

      {
        using Row = typename Mat::Row;

        Mat A(2, 2);
        std::fill(A.begin(), A.end(), false);
        REQUIRE(A.number_of_rows() == 2);
        REQUIRE(A.number_of_cols() == 2);
        REQUIRE(A == Mat({{falsefalse}, {falsefalse}}));

        A(0, 0) = true;
        A(1, 1) = true;
        REQUIRE(A == Mat({{truefalse}, {falsetrue}}));

        Mat B(2, 2);
        B(0, 1) = true;
        B(1, 0) = true;
        B(0, 0) = false;
        B(1, 1) = false;
        REQUIRE(B == Mat({{falsetrue}, {truefalse}}));

        REQUIRE(A + B == Mat({{truetrue}, {truetrue}}));
        REQUIRE(A * B == B);
        REQUIRE(B * A == B);
        REQUIRE(B * B == A);
        REQUIRE((A + B) * B == Mat({{truetrue}, {truetrue}}));

        Row C({0, 1});
        REQUIRE(C.number_of_rows() == 1);
        REQUIRE(C.number_of_cols() == 2);

        auto rv = A.row(0);
        Row  D(rv);
        REQUIRE(D.number_of_rows() == 1);
        REQUIRE(D.number_of_cols() == 2);
        REQUIRE(D != C);
        auto views = matrix_helpers::rows(A);
        REQUIRE(B < A);
        B.swap(A);
        REQUIRE(A < B);
        std::swap(B, A);
        REQUIRE(B < A);
        REQUIRE(views[0] == Row({truefalse}));
        REQUIRE(Row({truefalse}) == views[0]);
        REQUIRE(Row({truetrue}) != views[0]);
        REQUIRE(Row({falsefalse}) < views[0]);
        REQUIRE(A.hash_value() != 0);
        A *= false;
        REQUIRE(A == Mat({{falsefalse}, {falsefalse}}));
        auto r = Row({truefalse});
        views  = matrix_helpers::rows(B);
        REQUIRE(views[0].size() == 2);
        r += views[0];
        REQUIRE(r.number_of_cols() == 2);
        REQUIRE(r.number_of_rows() == 1);
        REQUIRE(r == Row({truetrue}));

        auto E = Mat::identity(2);
        REQUIRE(E.number_of_rows() == 2);
        REQUIRE(E.number_of_cols() == 2);
        auto viewse = matrix_helpers::rows(E);
        REQUIRE(viewse.size() == 2);

        std::ostringstream oss;
        oss << E;  // Does not do anything visible

        std::stringbuf buff;
        std::ostream   os(&buff);
        os << E;  // Also does not do anything visible
      }
      {
        Mat m({{0, 0}, {0, 0}});
        using scalar_type = typename Mat::scalar_type;
        auto it           = m.cbegin();
        REQUIRE(m.coords(it) == std::pair<scalar_type, scalar_type>({0, 0}));
        REQUIRE(m.coords(++it) == std::pair<scalar_type, scalar_type>({0, 1}));
        REQUIRE(m.coords(++it) == std::pair<scalar_type, scalar_type>({1, 0}));
        REQUIRE(m.coords(++it) == std::pair<scalar_type, scalar_type>({1, 1}));
      }
      {
        REQUIRE_THROWS_AS(Mat::make({{0, 0}, {0, 2}}), LibsemigroupsException);
      }
    }

    template <typename Mat>
    void test_BMat001() {
      auto x = Mat({{1, 0, 1}, {0, 1, 0}, {0, 1, 0}});
      auto y = Mat({{0, 0, 0}, {0, 0, 0}, {0, 0, 0}});
      auto z = Mat({{0, 0, 0}, {0, 0, 0}, {0, 0, 0}});
      REQUIRE(y == z);
      z.product_inplace(x, y);
      REQUIRE(y == z);
      z.product_inplace(y, x);
      REQUIRE(y == z);
      REQUIRE(!(y < z));
      auto id = x.identity();
      z.product_inplace(id, x);
      REQUIRE(z == x);
      z.product_inplace(x, id);
      REQUIRE(z == x);
      REQUIRE(x.hash_value() != 0);
    }

    template <typename Mat>
    void test_BMat002() {
      using RowView = typename Mat::RowView;
      auto x        = Mat::make({{1, 0, 0}, {1, 0, 0}, {1, 0, 0}});
      REQUIRE(matrix_helpers::row_basis(x).size() == 1);
      REQUIRE(matrix_helpers::row_space_size(x) == 1);
      x = Mat::make({{1, 0, 0}, {1, 1, 0}, {1, 1, 1}});
      REQUIRE(matrix_helpers::row_basis(x).size() == 3);
      REQUIRE_THROWS_AS(x.row(3), LibsemigroupsException);
      std::vector<RowView> v = {x.row(0), x.row(2)};
      REQUIRE(matrix_helpers::row_basis<Mat>(v).size() == 2);
      REQUIRE(matrix_helpers::row_space_size(x) == 3);
      x = Mat::make({{1, 0, 0}, {0, 1, 1}, {1, 1, 1}});
      REQUIRE(matrix_helpers::row_basis(x).size() == 2);
      REQUIRE(matrix_helpers::row_space_size(x) == 3);
      x = Mat::make({{1, 0, 0}, {0, 0, 1}, {0, 1, 0}});
      REQUIRE(matrix_helpers::row_space_size(x) == 7);
      std::vector<typename Mat::RowView> views;
      std::vector<typename Mat::RowView> result;
      matrix_helpers::row_basis<Mat, std::vector<typename Mat::RowView>&>(
          views, result);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - NTPMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_NTPMat000(NTPSemiring<> const* sr = nullptr) {
      using Row = typename Mat::Row;
      auto rg   = ReportGuard(REPORT);
      Mat  m(sr, 3, 3);
      // REQUIRE(validate(m)); // m might not be valid!
      m.product_inplace(Mat::make(sr, {{1, 1, 0}, {0, 0, 1}, {1, 0, 1}}),
                        Mat::make(sr, {{1, 0, 1}, {0, 0, 1}, {1, 1, 0}}));
      REQUIRE(m == Mat::make(sr, {{1, 0, 2}, {1, 1, 0}, {2, 1, 1}}));
      REQUIRE(m.row(0) == Row(sr, {1, 0, 2}));
      REQUIRE(m.row(0).size() == 3);
      auto r = matrix_helpers::rows(m);
      REQUIRE(r[0] == Row(sr, {1, 0, 2}));
      REQUIRE(r[1] == Row(sr, {1, 1, 0}));
      REQUIRE(r[2] == Row(sr, {2, 1, 1}));
      REQUIRE(m * Mat::identity(sr, 3) == m);
      REQUIRE(Mat::identity(sr, 3) * m == m);
    }

    template <typename Mat>
    void test_NTPMat001(NTPSemiring<> const* sr = nullptr) {
      using Row         = typename Mat::Row;
      using RowView     = typename Mat::RowView;
      using scalar_type = typename Mat::scalar_type;

      auto rg = ReportGuard(REPORT);

      Mat m = Mat::make(
          sr, {{1, 1, 0, 0}, {2, 0, 2, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}});
      REQUIRE(m.number_of_cols() == 4);
      REQUIRE(m.number_of_rows() == 4);
      auto r = matrix_helpers::rows(m);
      REQUIRE(r.size() == 4);
      REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
              == std::vector<scalar_type>({1, 1, 0, 0}));
      r[0] += r[1];
      REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
              == std::vector<scalar_type>({3, 1, 2, 0}));
      REQUIRE(std::vector<scalar_type>(r[1].cbegin(), r[1].cend())
              == std::vector<scalar_type>({2, 0, 2, 0}));
      REQUIRE(
          m
          == Mat::make(
              sr, {{3, 1, 2, 0}, {2, 0, 2, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}}));
      REQUIRE(r[0][0] == 3);
      REQUIRE(r[0](0) == 3);
      REQUIRE(r[2](3) == 9);
      std::sort(r[0].begin(), r[0].end());
      REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
              == std::vector<scalar_type>({0, 1, 2, 3}));
      REQUIRE(
          m
          == Mat::make(
              sr, {{0, 1, 2, 3}, {2, 0, 2, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}}));
      r[0] += 9;
      REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
              == std::vector<scalar_type>({9, 0, 1, 2}));
      REQUIRE(
          m
          == Mat::make(
              sr, {{9, 0, 1, 2}, {2, 0, 2, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}}));
      r[1] *= 3;
      REQUIRE(
          m
          == Mat::make(
              sr, {{9, 0, 1, 2}, {6, 0, 6, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}}));
      REQUIRE(std::vector<scalar_type>(r[1].cbegin(), r[1].cend())
              == std::vector<scalar_type>({6, 0, 6, 0}));
      REQUIRE(r[2] < r[1]);
      r[1] = r[2];
      REQUIRE(
          m
          == Mat::make(
              sr, {{9, 0, 1, 2}, {6, 0, 6, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}}));
      REQUIRE(r[1] == r[2]);
      REQUIRE(r[1] == Row::make(sr, {{1, 2, 3, 9}}));

      RowView rv;
      {
        rv = r[0];
        REQUIRE(rv == r[0]);
        REQUIRE(&rv != &r[0]);
      }
    }

    template <typename Mat>
    void test_NTPMat002(NTPSemiring<> const* sr = nullptr) {
      using Row = typename Mat::Row;

      auto rg = ReportGuard(REPORT);
      Mat  m(sr, {{1, 1, 0, 0}, {2, 0, 2, 0}, {1, 2, 3, 9}, {0, 0, 0, 7}});
      REQUIRE(m.number_of_cols() == 4);
      REQUIRE(m.number_of_rows() == 4);
      auto r = matrix_helpers::rows(m);
      REQUIRE(r.size() == 4);
      REQUIRE(r[0] == Row::make(sr, {{1, 1, 0, 0}}));
      REQUIRE(r[1] == Row::make(sr, {{2, 0, 2, 0}}));
      REQUIRE(r[0] != Row::make(sr, {{2, 0, 2, 0}}));
      REQUIRE(r[1] != Row::make(sr, {{1, 1, 0, 0}}));
      REQUIRE(Row::make(sr, {{1, 1, 0, 0}}) == r[0]);
      REQUIRE(Row::make(sr, {{2, 0, 2, 0}}) == r[1]);
      REQUIRE(Row::make(sr, {{2, 0, 2, 0}}) != r[0]);
      REQUIRE(Row::make(sr, {{1, 1, 0, 0}}) != r[1]);
      REQUIRE(Row::make(sr, {{1, 1, 0, 0}}) < Row(sr, {{9, 9, 9, 9}}));
      REQUIRE(r[0] < Row::make(sr, {{9, 9, 9, 9}}));
      REQUIRE(!(Row::make(sr, {{9, 9, 9, 9}}) < r[0]));
      Row x(r[3]);
      x *= 3;
      REQUIRE(x == Row::make(sr, {{0, 0, 0, 1}}));
      REQUIRE(x.number_of_rows() == 1);
      REQUIRE(x.number_of_cols() == 4);
      REQUIRE(r[3] == Row::make(sr, {{0, 0, 0, 7}}));
      REQUIRE(r[3] != x);
      REQUIRE(x != r[3]);
      REQUIRE(!(x != x));
    }

    template <typename Mat>
    void test_NTPMat003(NTPSemiring<> const* sr = nullptr) {
      auto x        = Mat::make(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
      auto expected = Mat::make(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
      REQUIRE(x == expected);
      REQUIRE(x.number_of_cols() == 3);
      REQUIRE(x.number_of_rows() == 3);

      auto y = Mat::make(sr, {{10, 0, 0}, {0, 1, 0}, {1, 1, 0}});
      REQUIRE(!(x == y));

      y.product_inplace(x, x);
      expected = Mat::make(sr, {{34, 34, 0}, {34, 34, 0}, {33, 33, 1}});
      REQUIRE(y == expected);

      REQUIRE(x < y);
      auto id = x.identity();
      y.product_inplace(id, x);
      REQUIRE(y == x);
      y.product_inplace(x, id);
      REQUIRE(y == x);
      REQUIRE(Hash<Mat>()(y) != 0);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - MaxPlusTruncMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_MaxPlusTruncMat000(MaxPlusTruncSemiring<> const* sr = nullptr) {
      using scalar_type = typename Mat::scalar_type;
      {
        Mat m1(sr, 2, 2);
        std::fill(m1.begin(), m1.end(), NEGATIVE_INFINITY);
        REQUIRE(m1
                == Mat::make(sr,
                             {{NEGATIVE_INFINITY, NEGATIVE_INFINITY},
                              {NEGATIVE_INFINITY, NEGATIVE_INFINITY}}));
        Mat m2(sr, 2, 2);
        std::fill(m2.begin(), m2.end(), 4);
        REQUIRE(m1 + m2 == m2);
        REQUIRE(m2(0, 1) == 4);
      }

      auto rg = ReportGuard(REPORT);
      {
        std::vector<std::array<scalar_type, 2>> expected;
        expected.push_back({1, 1});
        expected.push_back({0, 0});
        tropical_max_plus_row_basis<2, 5>(expected);
        REQUIRE(expected.size() == 1);
        REQUIRE(expected.at(0) == std::array<scalar_type, 2>({0, 0}));

        Mat  m(sr, {{1, 1}, {0, 0}});
        auto r = matrix_helpers::row_basis(m);
        REQUIRE(r.size() == 1);
        REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
                == std::vector<scalar_type>({0, 0}));
      }
      {
        Mat m(sr, {{1, 1}, {0, 0}});
        m      = m.identity();
        auto r = matrix_helpers::row_basis(m);
        REQUIRE(r.size() == 2);
        REQUIRE(std::vector<scalar_type>(r[0].cbegin(), r[0].cend())
                == std::vector<scalar_type>({NEGATIVE_INFINITY, 0}));
        REQUIRE(std::vector<scalar_type>(r[1].cbegin(), r[1].cend())
                == std::vector<scalar_type>({0, NEGATIVE_INFINITY}));
      }
      std::vector<typename Mat::RowView> views;
      std::vector<typename Mat::RowView> result;
      matrix_helpers::row_basis<Mat>(views, result);
    }

    template <typename Mat>
    void test_MaxPlusTruncMat001(MaxPlusTruncSemiring<> const* sr = nullptr) {
      // Threshold 5, 4 x 4
      using scalar_type = typename Mat::scalar_type;
      using Row         = typename Mat::Row;

      auto m  = Mat::make(sr,
                          {{2, 2, 0, 1},
                           {0, 0, 1, 3},
                           {1, NEGATIVE_INFINITY, 0, 0},
                           {0, 1, 0, 1}});
      auto rg = ReportGuard(REPORT);
      auto r  = matrix_helpers::row_basis(m);
      REQUIRE(r.size() == 4);
      REQUIRE(r[0] == Row::make(sr, {0, 0, 1, 3}));
      REQUIRE(r[1] == Row::make(sr, {0, 1, 0, 1}));
      REQUIRE(r[2] == Row::make(sr, {1, NEGATIVE_INFINITY, 0, 0}));
      REQUIRE(r[3] == Row::make(sr, {2, 2, 0, 1}));
      m.transpose();
      REQUIRE(m
              == Mat::make(sr,
                           {{2, 0, 1, 0},
                            {2, 0, NEGATIVE_INFINITY, 1},
                            {0, 1, 0, 0},
                            {1, 3, 0, 1}}));
      m.transpose();
      REQUIRE(m
              == Mat::make(sr,
                           {{2, 2, 0, 1},
                            {0, 0, 1, 3},
                            {1, NEGATIVE_INFINITY, 0, 0},
                            {0, 1, 0, 1}}));

      std::vector<std::array<scalar_type, 4>> expected;
      expected.push_back({2, 2, 0, 1});
      expected.push_back({0, 0, 1, 3});
      expected.push_back({1, NEGATIVE_INFINITY, 0, 0});
      expected.push_back({0, 1, 0, 1});
      tropical_max_plus_row_basis<4, 5>(expected);
      REQUIRE(expected.size() == 4);
      REQUIRE(m * Mat::identity(sr, 4) == m);
      REQUIRE(Mat::identity(sr, 4) * m == m);
    }

    template <typename Mat>
    void test_MaxPlusTruncMat002(MaxPlusTruncSemiring<> const* sr = nullptr) {
      auto x        = Mat(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
      auto expected = Mat(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
      REQUIRE(x == expected);

      REQUIRE_THROWS_AS(Mat::make(sr, {{-100, 0, 0}, {0, 1, 0}, {1, -1, 0}}),
                        LibsemigroupsException);
      auto y = Mat(sr, {{10, 0, 0}, {0, 1, 0}, {1, 1, 0}});
      REQUIRE(!(x == y));

      y.product_inplace(x, x);
      expected = Mat(sr, {{33, 33, 22}, {32, 32, 10}, {33, 33, 32}});
      REQUIRE(y == expected);

      REQUIRE(x < y);
      auto id = x.identity();
      y.product_inplace(id, x);
      REQUIRE(y == x);
      y.product_inplace(x, id);
      REQUIRE(y == x);
      REQUIRE(Hash<Mat>()(y) != 0);
      REQUIRE(x * Mat::identity(sr, 3) == x);
      REQUIRE(Mat::identity(sr, 3) * x == x);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - IntMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_IntMat000() {
      {
        auto x        = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        auto expected = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        REQUIRE(x == expected);

        auto y = Mat({{-100, 0, 0}, {0, 1, 0}, {1, -1, 0}});
        REQUIRE(!(x == y));

        y.product_inplace(x, x);
        expected = Mat({{2, -4, 0}, {2, -2, 0}, {2, -1, 1}});
        REQUIRE(y == expected);
        REQUIRE(y.number_of_rows() == 3);

        REQUIRE(x < y);
        REQUIRE(Degree<Mat>()(x) == 3);
        REQUIRE(Degree<Mat>()(y) == 3);
        REQUIRE(Complexity<Mat>()(x) == 27);
        REQUIRE(Complexity<Mat>()(y) == 27);
        auto id = x.identity();
        y.product_inplace(id, x);
        REQUIRE(y == x);
        y.product_inplace(x, id);
        REQUIRE(y == x);
      }
      {
        auto x        = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        auto expected = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        REQUIRE(x == expected);

        auto y = Mat({{-100, 0, 0}, {0, 1, 0}, {1, -1, 0}});
        REQUIRE(!(x == y));

        y.product_inplace(x, x);
        expected = Mat({{2, -4, 0}, {2, -2, 0}, {2, -1, 1}});
        REQUIRE(y == expected);

        REQUIRE(x < y);
        auto id = x.identity();
        y.product_inplace(id, x);
        REQUIRE(y == x);
        y.product_inplace(x, id);
        REQUIRE(y == x);
        REQUIRE(Hash<Mat>()(y) != 0);
      }
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - MaxPlusMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_MaxPlusMat000() {
      auto x        = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
      auto expected = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
      REQUIRE(x == expected);

      auto y = Mat{{-100, 0, 0}, {0, 1, 0}, {1, -1, 0}};
      REQUIRE(!(x == y));
      REQUIRE(x != y);

      y.product_inplace(x, x);
      expected = Mat({{1, 2, 2}, {1, 1, 1}, {2, 3, 2}});
      REQUIRE(y == expected);

      REQUIRE(x < y);
      REQUIRE(Degree<Mat>()(x) == 3);
      REQUIRE(Degree<Mat>()(y) == 3);
      REQUIRE(Complexity<Mat>()(x) == 27);
      REQUIRE(Complexity<Mat>()(y) == 27);
      auto id = x.identity();
      y.product_inplace(id, x);
      REQUIRE(y == x);
      y.product_inplace(x, id);
      REQUIRE(y == x);
      REQUIRE(Hash<Mat>()(y) != 0);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - MinPlusMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_MinPlusMat000() {
      {
        auto x        = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        auto expected = Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
        // Just testing the below doesn't compile
        // matrix_helpers::row_basis(x);
        REQUIRE(x == expected);

        auto y = Mat({{-100, 0, 0}, {0, 1, 0}, {1, -1, 0}});
        REQUIRE(!(x == y));

        y.product_inplace(x, x);
        expected = Mat({{-4, -3, -2}, {-3, -3, -1}, {-4, -3, -3}});
        REQUIRE(y == expected);

        REQUIRE(!(x < y));
        REQUIRE(Degree<Mat>()(x) == 3);
        REQUIRE(Degree<Mat>()(y) == 3);
        REQUIRE(Complexity<Mat>()(x) == 27);
        REQUIRE(Complexity<Mat>()(y) == 27);
        auto id = x.identity();
        y.product_inplace(id, x);
        REQUIRE(y == x);
        y.product_inplace(x, id);
        REQUIRE(y == x);
      }
      {
        auto x        = Mat({{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
        auto expected = Mat({{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
        REQUIRE(x == expected);

        auto y = Mat({{10, 0, 0}, {0, 1, 0}, {1, 1, 0}});
        REQUIRE(!(x == y));

        y.product_inplace(x, x);
        REQUIRE(y == Mat({{1, 21, 1}, {1, 0, 0}, {2, 22, 1}}));

        REQUIRE(x > y);
        REQUIRE(Degree<Mat>()(x) == 3);
        REQUIRE(Degree<Mat>()(y) == 3);
        REQUIRE(Complexity<Mat>()(x) == 27);
        REQUIRE(Complexity<Mat>()(y) == 27);
        auto id = x.identity();
        y.product_inplace(id, x);
        REQUIRE(y == x);
        y.product_inplace(x, id);
        REQUIRE(y == x);
        REQUIRE(Hash<Mat>()(y) != 0);
      }
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - MinPlusTruncMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_MinPlusTruncMat000(MinPlusTruncSemiring<> const* sr = nullptr) {
      auto x = Mat(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});

      auto expected = Mat::make(sr, {{22, 21, 0}, {10, 0, 0}, {1, 32, 1}});
      REQUIRE(x == expected);

      auto y = Mat(sr, {{10, 0, 0}, {0, 1, 0}, {1, 1, 0}});
      REQUIRE(!(x == y));

      y.product_inplace(x, x);
      expected = Mat(sr, {{1, 21, 1}, {1, 0, 0}, {2, 22, 1}});
      REQUIRE(y == expected);

      REQUIRE(!(x < y));
      REQUIRE(Degree<Mat>()(x) == 3);
      REQUIRE(Degree<Mat>()(y) == 3);
      REQUIRE(Complexity<Mat>()(x) == 27);
      REQUIRE(Complexity<Mat>()(y) == 27);
      auto id = x.identity();
      y.product_inplace(id, x);
      REQUIRE(y == x);
      y.product_inplace(x, id);
      REQUIRE(y == x);
      REQUIRE(Hash<Mat>()(y) != 0);
      REQUIRE_THROWS_AS(Mat::make(sr, {{-22, 21, 0}, {10, 0, 0}, {1, 32, 1}}),
                        LibsemigroupsException);
      REQUIRE(x * Mat::identity(sr, 3) == x);
      REQUIRE(Mat::identity(sr, 3) * x == x);
    }

    ////////////////////////////////////////////////////////////////////////
    // Test functions - ProjMaxPlusMat
    ////////////////////////////////////////////////////////////////////////

    template <typename Mat>
    void test_ProjMaxPlusMat000() {
      using Row     = typename Mat::Row;
      auto x        = Mat::make({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}});
      auto expected = Mat::make({{-4, 0, -2}, {-3, -2, -2}, {-1, -5, -1}});
      REQUIRE(x == expected);
      REQUIRE(x.zero() == NEGATIVE_INFINITY);
      REQUIRE(x.one() == 0);

      auto y = Mat::make({{NEGATIVE_INFINITY, 0, 0}, {0, 1, 0}, {1, -1, 0}});
      expected
          = Mat::make({{NEGATIVE_INFINITY, -1, -1}, {-1, 0, -1}, {0, -2, -1}});
      REQUIRE(y == expected);
      REQUIRE(!(x == y));

      y.product_inplace(x, x);
      expected = Mat({{-2, -1, -1}, {-2, -2, -2}, {-1, 0, -1}});
      REQUIRE(y == expected);

      REQUIRE(x < y);
      REQUIRE(y > x);
      REQUIRE(Degree<Mat>()(x) == 3);
      REQUIRE(Degree<Mat>()(y) == 3);
      REQUIRE(Complexity<Mat>()(x) == 27);
      REQUIRE(Complexity<Mat>()(y) == 27);
      auto id = x.identity();
      y.product_inplace(id, x);
      REQUIRE(y == x);
      y.product_inplace(x, id);
      REQUIRE(y == x);

      REQUIRE(Mat::make({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}}).hash_value()
              != 0);

      y = x;
      REQUIRE(&x != &y);
      REQUIRE(x == y);
      REQUIRE(y == Mat::make(nullptr, {{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}}));

      auto yy(y);
      REQUIRE(yy == y);

      std::ostringstream oss;
      oss << y;  // Does not do anything visible
      std::stringbuf buff;
      std::ostream   os(&buff);
      os << y;  // Also does not do anything visible

      REQUIRE(y.row(0) == Row::make({-4, 0, -2}));
      REQUIRE(y.row(1) == Row({-3, -2, -2}));
      REQUIRE(Row(y.row(0)) == y.row(0));

      auto zz(std::move(y));

      Mat tt;
      REQUIRE(tt != zz);
      REQUIRE(Mat::identity(3)
              == Mat({{0, NEGATIVE_INFINITY, NEGATIVE_INFINITY},
                      {NEGATIVE_INFINITY, 0, NEGATIVE_INFINITY},
                      {NEGATIVE_INFINITY, NEGATIVE_INFINITY, 0}}));
      REQUIRE(zz(0, 0) == -4);
      REQUIRE(zz.number_of_cols() == 3);
      zz += zz;
      REQUIRE(zz == Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}}));
      zz *= 2;
      REQUIRE(zz == Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}}));
      REQUIRE(zz + x == Mat({{-2, 2, 0}, {-1, 0, 0}, {1, -3, 1}}));
      REQUIRE(zz * x == Mat({{-2, -1, -1}, {-2, -2, -2}, {-1, 0, -1}}));
      REQUIRE(std::accumulate(zz.cbegin(), zz.cend(), 0) == -20);
      REQUIRE(std::accumulate(zz.begin(), zz.end(), 0) == -20);
      x.transpose();
      REQUIRE(x == Mat({{-4, -3, -1}, {0, -2, -5}, {-2, -2, -1}}));
      x.swap(zz);
      REQUIRE(zz == Mat({{-4, -3, -1}, {0, -2, -5}, {-2, -2, -1}}));
      REQUIRE(matrix_helpers::pow(x, 100)
              == Mat({{-1, 0, -1}, {-2, -1, -2}, {-1, 0, -1}}));
      REQUIRE_THROWS_AS(matrix_helpers::pow(x, -100), LibsemigroupsException);
      REQUIRE(matrix_helpers::pow(x, 1)
              == Mat({{-4, 0, -2}, {-3, -2, -2}, {-1, -5, -1}}));
      REQUIRE(matrix_helpers::pow(x, 0) == Mat::identity(3));
    }

  }  // namespace

  ////////////////////////////////////////////////////////////////////////
  // Test cases - BMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""000""BMat<2>""[quick]") {
    test_BMat000<BMat<2>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""001""BMat<>""[quick]") {
    test_BMat000<BMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""002""BMat<3> + BMat<>""[quick]") {
    auto rg = ReportGuard(REPORT);
    {
      BMat<3> m;
      m.product_inplace(BMat<3>({{1, 1, 0}, {0, 0, 1}, {1, 0, 1}}),
                        BMat<3>({{1, 0, 1}, {0, 0, 1}, {1, 1, 0}}));
      REQUIRE(m == BMat<3>({{1, 0, 1}, {1, 1, 0}, {1, 1, 1}}));
    }
    {
      BMat<> m(3, 3);
      m.product_inplace(BMat<>({{1, 1, 0}, {0, 0, 1}, {1, 0, 1}}),
                        BMat<>({{1, 0, 1}, {0, 0, 1}, {1, 1, 0}}));
      REQUIRE(m == BMat<>({{1, 0, 1}, {1, 1, 0}, {1, 1, 1}}));
    }
    {
      BMat<>* A = new BMat<>();
      delete A;
      BMat<3>* B = new BMat<3>();
      delete B;
      BMat<3>::Row* C = new BMat<3>::Row();
      delete C;
      BMat<2>::Row* D = new BMat<2>::Row();
      delete D;
      BMat<2>* E = new BMat<2>();
      delete E;
    }
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""003""BMat<2> + BMat<>""[quick]") {
    BMat<2> AB;
    BMat<2> A;
    BMat<2> B;
    std::fill(A.begin(), A.end(), false);
    std::fill(B.begin(), B.end(), false);
    std::fill(AB.begin(), AB.end(), false);
    A(1, 1) = true;

    AB.product_inplace(A, B);
    REQUIRE(AB == B);

    REQUIRE(A.identity() == BMat<2>({{truefalse}, {falsetrue}}));

    BMat<> CD(2, 2);
    BMat<> C(2, 2);
    BMat<> D(2, 2);

    std::fill(CD.begin(), CD.end(), false);
    std::fill(D.begin(), D.end(), false);
    C(1, 1) = true;
    CD.product_inplace(C, D);
    REQUIRE(CD == D);
    REQUIRE(D.identity() == BMat<>({{truefalse}, {falsetrue}}));
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""004""BMat<3>""[quick]") {
    test_BMat001<BMat<3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""005""BMat<>""[quick]") {
    test_BMat001<BMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""006""BMat<3> row_basis""[quick]") {
    test_BMat002<BMat<3>>();
  }
  LIBSEMIGROUPS_TEST_CASE("Matrix""007""BMat<> row_basis""[quick]") {
    test_BMat002<BMat<>>();
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - IntMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""008""IntMat<3>""[quick]") {
    test_IntMat000<IntMat<3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""009""IntMat<>""[quick]") {
    test_IntMat000<IntMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""010""IntMat code cov""[quick]") {
    IntMat<>* A = new IntMat<>();
    delete A;
    IntMat<3>* B = new IntMat<3>();
    delete B;
    IntMat<3>::Row* C = new IntMat<3>::Row();
    delete C;
    IntMat<2>::Row* D = new IntMat<2>::Row();
    delete D;
    IntMat<2>* E = new IntMat<2>();
    delete E;
    IntMat<> F(3, 3);
    IntMat<> G(4, 4);
    std::swap(F, G);
    REQUIRE(G.number_of_cols() == 3);
    REQUIRE(G.number_of_rows() == 3);
    REQUIRE(F.number_of_cols() == 4);
    REQUIRE(F.number_of_rows() == 4);
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - MaxPlusMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""011""MaxPlusMat<3>""[quick]") {
    test_MaxPlusMat000<MaxPlusMat<3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""012""MaxPlusMat<>""[quick]") {
    test_MaxPlusMat000<MaxPlusMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""013""MaxPlusMat code cov""[quick]") {
    MaxPlusMat<3>* B = new MaxPlusMat<3>();
    delete B;
    MaxPlusMat<3>::Row* C = new MaxPlusMat<3>::Row();
    delete C;
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - MinPlusMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""014""MinPlusMat<3>""[quick]") {
    test_MinPlusMat000<MinPlusMat<3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""015""MinPlusMat<>""[quick]") {
    test_MinPlusMat000<MinPlusMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""016""MinPlusMat code cov""[quick]") {
    MinPlusMat<3>* B = new MinPlusMat<3>();
    delete B;
    MinPlusMat<3>::Row* C = new MinPlusMat<3>::Row();
    delete C;
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - MaxPlusTruncMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""017""MaxPlusTruncMat<5, 2>""[quick]") {
    // Threshold 5, 2 x 2
    test_MaxPlusTruncMat000<MaxPlusTruncMat<5, 2>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""018""MaxPlusTruncMat<5>""[quick]") {
    // Threshold 5, 2 x 2
    test_MaxPlusTruncMat000<MaxPlusTruncMat<5>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""019""MaxPlusTruncMat<>""[quick]") {
    // Threshold 5, 2 x 2 (specified in test_MaxPlusTruncMat000)
    REQUIRE_THROWS_AS(MaxPlusTruncSemiring<>(-1), LibsemigroupsException);
    MaxPlusTruncSemiring<> const* sr = new MaxPlusTruncSemiring<>(5);
    test_MaxPlusTruncMat000<MaxPlusTruncMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""020""MaxPlusTruncMat<5, 4>""[quick]") {
    // Threshold 5, 4 x 4
    test_MaxPlusTruncMat001<MaxPlusTruncMat<5, 4>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""021""MaxPlusTruncMat<5>""[quick]") {
    // Threshold 5, 4 x 4
    test_MaxPlusTruncMat001<MaxPlusTruncMat<5>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""022""MaxPlusTruncMat<>""[quick]") {
    // Threshold 5, 4 x 4
    MaxPlusTruncSemiring<> const* sr = new MaxPlusTruncSemiring<>(5);
    test_MaxPlusTruncMat001<MaxPlusTruncMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix",
                          "023",
                          "MaxPlusTruncMat<33, 3>",
                          "[quick]") {
    // Threshold 33, 3 x 3
    test_MaxPlusTruncMat002<MaxPlusTruncMat<33, 3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""024""MaxPlusTruncMat<33>""[quick]") {
    // Threshold 33, 3 x 3
    test_MaxPlusTruncMat002<MaxPlusTruncMat<33>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""025""MaxPlusTruncMat<>""[quick]") {
    // Threshold 33, 3 x 3
    MaxPlusTruncSemiring<> const* sr = new MaxPlusTruncSemiring<>(33);
    test_MaxPlusTruncMat002<MaxPlusTruncMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""026""MaxPlusMat code cov""[quick]") {
    MaxPlusTruncMat<33, 3>* B = new MaxPlusTruncMat<33, 3>();
    delete B;
    MaxPlusTruncMat<5, 2>::Row* C = new MaxPlusTruncMat<5, 2>::Row();
    delete C;
    MaxPlusTruncMat<5, 4>::Row* D = new MaxPlusTruncMat<5, 4>::Row();
    delete D;
    auto x = MaxPlusTruncMat<5, 2>();
    REQUIRE(x.number_of_rows() == 2);
    MaxPlusTruncMat<5, 2>* E = new MaxPlusTruncMat<5, 2>();
    delete E;
    MaxPlusTruncMat<5, 4>* F = new MaxPlusTruncMat<5, 4>();
    delete F;
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - MinPlusTruncMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix",
                          "027",
                          "MinPlusTruncMat<33, 3>",
                          "[quick]") {
    // 3 x 3 matrices with threshold 33
    test_MinPlusTruncMat000<MinPlusTruncMat<33, 3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""028""MinPlusTruncMat<33>""[quick]") {
    // 3 x 3 matrices with threshold 33
    test_MinPlusTruncMat000<MinPlusTruncMat<33>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""029""MinPlusTruncMat<>""[quick]") {
    // 3 x 3 matrices with threshold 33
    REQUIRE_THROWS_AS(MinPlusTruncSemiring<>(-1), LibsemigroupsException);
    MinPlusTruncSemiring<> const* sr = new MinPlusTruncSemiring<>(33);
    test_MinPlusTruncMat000<MinPlusTruncMat<>>(sr);
    delete sr;
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - NTPMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""030""NTPMat<0, 3, 3, 3>""[quick]") {
    test_NTPMat000<NTPMat<0, 3, 3, 3>>();
    test_NTPMat000<NTPMat<0, 3, 3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""031""NTPMat<0, 3>""[quick]") {
    test_NTPMat000<NTPMat<0, 3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""032""NTPMat<>""[quick]") {
    REQUIRE_THROWS_AS(NTPSemiring<int>(4, -1), LibsemigroupsException);
    REQUIRE_THROWS_AS(NTPSemiring<int>(-1, -1), LibsemigroupsException);
    NTPSemiring<> const* sr = new NTPSemiring<>(0, 3);
    test_NTPMat000<NTPMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""033""NTPMat<0, 10, 4, 4>""[quick]") {
    test_NTPMat001<NTPMat<0, 10, 4, 4>>();
    test_NTPMat001<NTPMat<0, 10, 4>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""034""NTPMat<0, 10>""[quick]") {
    test_NTPMat001<NTPMat<0, 10>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""035""NTPMat<>""[quick]") {
    NTPSemiring<> const* sr = new NTPSemiring<>(0, 10);
    test_NTPMat001<NTPMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""036""NTPMat<0, 10, 4, 4>""[quick]") {
    test_NTPMat002<NTPMat<0, 10, 4, 4>>();
    test_NTPMat002<NTPMat<0, 10, 4>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""037""NTPMat<0, 10>""[quick]") {
    test_NTPMat002<NTPMat<0, 10>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""038""NTPMat<>""[quick]") {
    NTPSemiring<> const* sr = new NTPSemiring<>(0, 10);
    test_NTPMat002<NTPMat<>>(sr);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""039""NTPMat<33, 2, 3, 3>""[quick]") {
    test_NTPMat003<NTPMat<33, 2, 3, 3>>();
    test_NTPMat003<NTPMat<33, 2, 3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""040""NTPMat<33, 2>""[quick]") {
    test_NTPMat003<NTPMat<33, 2>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""041""NTPMat<>""[quick]") {
    NTPSemiring<> const* sr = new NTPSemiring<>(33, 2);
    test_NTPMat003<NTPMat<>>(sr);
    delete sr;
  }

  ////////////////////////////////////////////////////////////////////////
  // Test cases - ProjMaxPlusMat
  ////////////////////////////////////////////////////////////////////////

  LIBSEMIGROUPS_TEST_CASE("Matrix""042""ProjMaxPlusMat<3>""[quick]") {
    test_ProjMaxPlusMat000<ProjMaxPlusMat<3, 3>>();
    test_ProjMaxPlusMat000<ProjMaxPlusMat<3>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""043""ProjMaxPlusMat<>""[quick]") {
    test_ProjMaxPlusMat000<ProjMaxPlusMat<>>();
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""044""exceptions""[quick][element]") {
    using Mat               = NTPMat<>;
    using scalar_type       = typename Mat::scalar_type;
    NTPSemiring<> const* sr = new NTPSemiring<>(23, 1);
    REQUIRE(sr->one() == 1);
    REQUIRE(sr->zero() == 0);
    REQUIRE_THROWS_AS(Mat::make(nullptr, {{0, 0}, {0, 0}}),
                      LibsemigroupsException);
    auto x = Mat::make(sr, std::vector<std::vector<scalar_type>>());
    REQUIRE(x.number_of_cols() == x.number_of_rows());
    REQUIRE(x.number_of_cols() == 0);

    REQUIRE_THROWS_AS(Mat::make(sr, {{2, 2, 0}, {0, 0, 140}, {1, 3, 1}}),
                      LibsemigroupsException);
    delete sr;
  }

  LIBSEMIGROUPS_TEST_CASE("Matrix""045""code coverage""[quick]") {
    {
      BMat<> x(0, 0);
      x.transpose();
      REQUIRE(x == x);
      BMat<> y(2, 1);
      REQUIRE_THROWS_AS(matrix_helpers::pow(y, 2), LibsemigroupsException);
    }
    { REQUIRE_THROWS_AS(BMat<>::make({{0, 1}, {0}}), LibsemigroupsException); }
    {
      BMat<> y(2, 2);
      std::fill(y.begin(), y.end(), 0);
      auto        r   = matrix_helpers::rows(y);
      auto const& val = r[0](0);
      REQUIRE(!val);
      REQUIRE(r[0] + r[1] == r[0]);
      std::ostringstream oss;
      oss << r[0];  // Does not do anything visible
      std::stringbuf buff;
      std::ostream   os(&buff);
      os << r[0];  // Also does not do anything visible
    }
    {
      using Row = BMat<2>::Row;
      BMat<2> x;
      std::fill(x.begin(), x.end(), 1);
      auto r = matrix_helpers::rows(x);
      Row  y(nullptr, r[0]);
      REQUIRE(y == Row({1, 1}));
    }
    {
      std::vector<std::vector<int>> v = {{truefalse}, {truefalse}};
      BMat<>                        x(v);
      REQUIRE(x == BMat<>({{truefalse}, {truefalse}}));
    }
    { BMat<> x; }
    {
      using Mat               = NTPMat<>;
      NTPSemiring<> const* sr = new NTPSemiring<>(23, 1);
      auto                 x  = Mat(sr, {{0, 1}, {0, 2}});
      Mat                  y  = x;
      REQUIRE(x == y);
      REQUIRE(&x != &y);

      Mat z(std::move(x));
      REQUIRE(z == y);
      REQUIRE(&z != &y);
      z(1, 0) = 2;
      y.swap(z);
      REQUIRE(y(1, 0) == 2);
      REQUIRE(z(1, 0) == 0);
      delete sr;
    }
  }

  LIBSEMIGROUPS_TEST_CASE("FastestBMat",
                          "046",
                          "check no throw",
                          "[quick][matrix]") {
    REQUIRE_NOTHROW(FastestBMat<3>({{0, 1}, {0, 1}}));
  }

}  // namespace libsemigroups

96%


¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Normalansicht

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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 ist noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge