// 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
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|