// 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