// 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
Messung V0.5 in Prozent C=92 H=91 G=91
¤ Dauer der Verarbeitung: 0.58 Sekunden
(vorverarbeitet am 2026-06-17)
¤
*© Formatika GbR, Deutschland