// 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 >({true , true }));
REQUIRE(std::vector<bool >(r[1].cbegin(), r[1].cend())
== std::vector<bool >({false , false }));
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 >({false , false }));
REQUIRE(std::vector<bool >(r[1].cbegin(), r[1].cend())
== std::vector<bool >({true , true }));
}
{
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({{false , false }, {false , false }}));
A(0, 0) = true ;
A(1, 1) = true ;
REQUIRE(A == Mat({{true , false }, {false , true }}));
Mat B(2, 2);
B(0, 1) = true ;
B(1, 0) = true ;
B(0, 0) = false ;
B(1, 1) = false ;
REQUIRE(B == Mat({{false , true }, {true , false }}));
REQUIRE(A + B == Mat({{true , true }, {true , true }}));
REQUIRE(A * B == B);
REQUIRE(B * A == B);
REQUIRE(B * B == A);
REQUIRE((A + B) * B == Mat({{true , true }, {true , true }}));
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({true , false }));
REQUIRE(Row({true , false }) == views[0]);
REQUIRE(Row({true , true }) != views[0]);
REQUIRE(Row({false , false }) < views[0]);
REQUIRE(A.hash_value() != 0);
A *= false ;
REQUIRE(A == Mat({{false , false }, {false , false }}));
auto r = Row({true , false });
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({true , true }));
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>({{true , false }, {false , true }}));
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<>({{true , false }, {false , true }}));
}
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 = {{true , false }, {true , false }};
BMat<> x(v);
REQUIRE(x == BMat<>({{true , false }, {true , false }}));
}
{ 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
quality 96%
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland