19#ifndef LIBSEMIGROUPS_DETAIL_MATRIX_COMMON_HPP_
20#define LIBSEMIGROUPS_DETAIL_MATRIX_COMMON_HPP_
24#include <initializer_list>
34#include "libsemigroups/adapters.hpp"
35#include "libsemigroups/constants.hpp"
36#include "libsemigroups/debug.hpp"
37#include "libsemigroups/exception.hpp"
38#include "libsemigroups/is-matrix.hpp"
41#include "matrix-exceptions.hpp"
44namespace libsemigroups::detail {
53 template <
typename Scalar>
54 [[nodiscard]] std::string entry_repr(Scalar a);
56 template <
typename Container,
59 typename Semiring =
void>
60 class MatrixCommon : MatrixPolymorphicBase {
66 using scalar_type =
typename Container::value_type;
67 using scalar_reference =
typename Container::reference;
68 using scalar_const_reference =
typename Container::const_reference;
69 using semiring_type = Semiring;
71 using container_type = Container;
72 using iterator =
typename Container::iterator;
73 using const_iterator =
typename Container::const_iterator;
75 using RowView = TRowView;
77 [[nodiscard]] scalar_type scalar_one() const noexcept {
78 return static_cast<Subclass const*
>(
this)->one_impl();
81 [[nodiscard]] scalar_type scalar_zero() const noexcept {
82 return static_cast<Subclass const*
>(
this)->zero_impl();
85 [[nodiscard]] Semiring
const* semiring() const noexcept {
86 return static_cast<Subclass const*
>(
this)->semiring_impl();
94 [[nodiscard]] scalar_type plus_no_checks(scalar_type x,
95 scalar_type y)
const noexcept {
96 return static_cast<Subclass const*
>(
this)->plus_no_checks_impl(y, x);
99 [[nodiscard]] scalar_type product_no_checks(scalar_type x,
100 scalar_type y)
const noexcept {
101 return static_cast<Subclass const*
>(
this)->product_no_checks_impl(y, x);
109 void resize(
size_t r,
size_t c) {
110 if constexpr (std::is_same_v<container_type, std::vector<scalar_type>>) {
111 _container.resize(r * c);
117 template <
typename T>
118 void init(T
const& m);
122 init(std::initializer_list<std::initializer_list<scalar_type>>
const& m) {
123 init<std::initializer_list<std::initializer_list<scalar_type>>>(m);
132 MatrixCommon() =
default;
133 MatrixCommon(MatrixCommon
const&) =
default;
134 MatrixCommon(MatrixCommon&&) =
default;
135 MatrixCommon& operator=(MatrixCommon
const&) =
default;
136 MatrixCommon& operator=(MatrixCommon&&) =
default;
138 ~MatrixCommon() =
default;
140 explicit MatrixCommon(std::initializer_list<scalar_type>
const& c)
146 explicit MatrixCommon(std::vector<std::vector<scalar_type>>
const& m)
152 std::initializer_list<std::initializer_list<scalar_type>>
const& m)
158 explicit MatrixCommon(RowView
const& rv) : MatrixCommon() {
159 resize(1, rv.size());
160 std::copy(rv.cbegin(), rv.cend(), _container.begin());
164 [[nodiscard]] Subclass one()
const;
171 [[nodiscard]]
bool operator==(MatrixCommon
const& that)
const {
172 return _container == that._container;
176 [[nodiscard]]
bool operator==(RowView
const& that)
const {
177 return number_of_rows() == 1
178 &&
static_cast<RowView
>(*
static_cast<Subclass const*
>(
this))
183 [[nodiscard]]
bool operator<(MatrixCommon
const& that)
const {
184 return _container < that._container;
188 [[nodiscard]]
bool operator<(RowView
const& that)
const {
189 return number_of_rows() == 1
190 &&
static_cast<RowView
>(*
static_cast<Subclass const*
>(
this))
195 template <
typename T>
196 [[nodiscard]]
bool operator!=(T
const& that)
const {
197 static_assert(
IsMatrix<T> || std::is_same_v<T, RowView>);
198 return !(*
this == that);
202 template <
typename T>
203 [[nodiscard]]
bool operator>(T
const& that)
const {
204 static_assert(
IsMatrix<T> || std::is_same_v<T, RowView>);
209 template <
typename T>
210 [[nodiscard]]
bool operator>=(T
const& that)
const {
211 static_assert(
IsMatrix<T> || std::is_same_v<T, RowView>);
212 return that < *
this || that == *
this;
216 template <
typename T>
217 [[nodiscard]]
bool operator<=(T
const& that)
const {
218 static_assert(
IsMatrix<T> || std::is_same_v<T, RowView>);
219 return *
this < that || that == *
this;
228 [[nodiscard]] scalar_reference operator()(
size_t r,
size_t c) {
229 return this->_container[r * number_of_cols() + c];
232 [[nodiscard]] scalar_reference at(
size_t r,
size_t c) {
234 return this->operator()(r, c);
239 [[nodiscard]] scalar_const_reference operator()(
size_t r,
size_t c)
const {
240 return this->_container[r * number_of_cols() + c];
243 [[nodiscard]] scalar_const_reference at(
size_t r,
size_t c)
const {
245 return this->operator()(r, c);
249 [[nodiscard]]
size_t number_of_rows() const noexcept {
250 return static_cast<Subclass const*
>(
this)->number_of_rows_impl();
254 [[nodiscard]]
size_t number_of_cols() const noexcept {
255 return static_cast<Subclass const*
>(
this)->number_of_cols_impl();
259 [[nodiscard]]
size_t hash_value()
const {
260 return Hash<Container>()(_container);
268 void product_inplace_no_checks(Subclass
const& A, Subclass
const& B);
269 void product_inplace(Subclass
const& A, Subclass
const& B);
272 void operator*=(scalar_type a) {
273 for (
auto it = _container.begin(); it < _container.end(); ++it) {
274 *it = product_no_checks(*it, a);
278 void plus_inplace_no_checks(Subclass
const& that);
281 void operator+=(Subclass
const& that);
283 void plus_inplace_no_checks(RowView
const& that) {
284 LIBSEMIGROUPS_ASSERT(number_of_rows() == 1);
285 LIBSEMIGROUPS_ASSERT(number_of_cols() == that.size());
286 RowView(*
static_cast<Subclass const*
>(
this)) += that;
289 void operator+=(RowView
const& that);
291 void operator+=(scalar_type a) {
292 for (
auto it = _container.begin(); it < _container.end(); ++it) {
293 *it = plus_no_checks(*it, a);
303 [[nodiscard]] Subclass plus_no_checks(Subclass
const& y)
const {
304 Subclass result(*
static_cast<Subclass const*
>(
this));
305 result.plus_inplace_no_checks(y);
309 [[nodiscard]] Subclass operator+(Subclass
const& y)
const;
311 [[nodiscard]] Subclass product_no_checks(Subclass
const& y)
const {
312 Subclass result(*
static_cast<Subclass const*
>(
this));
313 result.product_inplace_no_checks(*
static_cast<Subclass const*
>(
this), y);
318 [[nodiscard]] Subclass operator*(Subclass
const& y)
const;
320 [[nodiscard]] Subclass operator*(scalar_type a)
const {
321 Subclass result(*
static_cast<Subclass const*
>(
this));
326 [[nodiscard]] Subclass operator+(scalar_type a)
const {
327 Subclass result(*
static_cast<Subclass const*
>(
this));
337 [[nodiscard]] iterator begin() noexcept {
338 return _container.begin();
342 [[nodiscard]] iterator end() noexcept {
343 return _container.end();
347 [[nodiscard]] const_iterator begin() const noexcept {
348 return _container.begin();
352 [[nodiscard]] const_iterator end() const noexcept {
353 return _container.end();
357 [[nodiscard]] const_iterator cbegin() const noexcept {
358 return _container.cbegin();
362 [[nodiscard]] const_iterator cend() const noexcept {
363 return _container.cend();
366 template <
typename Iterator>
367 [[nodiscard]] std::pair<scalar_type, scalar_type>
368 coords(Iterator
const& it)
const;
375 void swap(MatrixCommon& that)
noexcept {
381 void transpose_no_checks() noexcept;
385 transpose_no_checks();
393 [[nodiscard]] RowView row_no_checks(
size_t i)
const;
395 [[nodiscard]] RowView row(
size_t i)
const;
398 template <
typename T>
399 void rows(T& x)
const;
405 friend std::ostream& operator<<(std::ostream& os, MatrixCommon
const& x) {
406 os << detail::to_string(x);
414 container_type _container;
417 template <
typename Scalar>
418 class MatrixDynamicDim {
420 MatrixDynamicDim() : _number_of_cols(0), _number_of_rows(0) {}
421 MatrixDynamicDim(MatrixDynamicDim
const&) =
default;
422 MatrixDynamicDim(MatrixDynamicDim&&) =
default;
423 MatrixDynamicDim& operator=(MatrixDynamicDim
const&) =
default;
424 MatrixDynamicDim& operator=(MatrixDynamicDim&&) =
default;
426 MatrixDynamicDim(
size_t r,
size_t c)
427 : _number_of_cols(c), _number_of_rows(r) {}
429 ~MatrixDynamicDim() =
default;
431 void swap(MatrixDynamicDim& that)
noexcept {
432 std::swap(_number_of_cols, that._number_of_cols);
433 std::swap(_number_of_rows, that._number_of_rows);
437 [[nodiscard]]
size_t number_of_rows_impl() const noexcept {
438 return _number_of_rows;
441 [[nodiscard]]
size_t number_of_cols_impl() const noexcept {
442 return _number_of_cols;
446 size_t _number_of_cols;
447 size_t _number_of_rows;
450 template <
typename PlusOp,
455 struct MatrixStaticArithmetic {
456 MatrixStaticArithmetic() =
default;
457 MatrixStaticArithmetic(MatrixStaticArithmetic
const&) =
default;
458 MatrixStaticArithmetic(MatrixStaticArithmetic&&) =
default;
459 MatrixStaticArithmetic& operator=(MatrixStaticArithmetic
const&) =
default;
460 MatrixStaticArithmetic& operator=(MatrixStaticArithmetic&&) =
default;
462 using scalar_type = Scalar;
465 [[nodiscard]]
static constexpr scalar_type
466 plus_no_checks_impl(scalar_type x, scalar_type y)
noexcept {
467 return PlusOp()(x, y);
470 [[nodiscard]]
static constexpr scalar_type
471 product_no_checks_impl(scalar_type x, scalar_type y)
noexcept {
472 return ProdOp()(x, y);
475 [[nodiscard]]
static constexpr scalar_type one_impl() noexcept {
479 [[nodiscard]]
static constexpr scalar_type zero_impl() noexcept {
483 [[nodiscard]]
static constexpr void const* semiring_impl() noexcept {
492 template <
typename Mat,
typename Sub
class>
493 class RowViewCommon {
495 "the template parameter Mat must be derived from "
496 "MatrixPolymorphicBase");
499 using const_iterator =
typename Mat::const_iterator;
500 using iterator =
typename Mat::iterator;
502 using scalar_type =
typename Mat::scalar_type;
503 using scalar_reference =
typename Mat::scalar_reference;
504 using scalar_const_reference =
typename Mat::scalar_const_reference;
506 using Row =
typename Mat::Row;
507 using matrix_type = Mat;
509 [[nodiscard]]
size_t size() const noexcept {
510 return static_cast<Subclass const*
>(
this)->length_impl();
514 scalar_type plus_no_checks(scalar_type x, scalar_type y)
const noexcept {
515 return static_cast<Subclass const*
>(
this)->plus_no_checks_impl(y, x);
518 scalar_type product_no_checks(scalar_type x, scalar_type y)
const noexcept {
519 return static_cast<Subclass const*
>(
this)->product_no_checks_impl(y, x);
523 RowViewCommon() =
default;
524 RowViewCommon(RowViewCommon
const&) =
default;
525 RowViewCommon(RowViewCommon&&) =
default;
526 RowViewCommon& operator=(RowViewCommon
const&) =
default;
527 RowViewCommon& operator=(RowViewCommon&&) =
default;
529 ~RowViewCommon() =
default;
531 explicit RowViewCommon(Row
const& r)
532 : RowViewCommon(const_cast<Row&>(r).begin()) {}
535 [[nodiscard]] scalar_const_reference operator[](
size_t i)
const {
540 [[nodiscard]] scalar_reference operator[](
size_t i) {
545 [[nodiscard]] scalar_const_reference operator()(
size_t i)
const {
550 [[nodiscard]] scalar_reference operator()(
size_t i) {
555 [[nodiscard]] const_iterator cbegin() const noexcept {
560 [[nodiscard]] const_iterator cend()
const {
561 return _begin + size();
565 [[nodiscard]] const_iterator begin() const noexcept {
570 [[nodiscard]] const_iterator end()
const {
571 return _begin + size();
575 [[nodiscard]] iterator begin() noexcept {
580 [[nodiscard]] iterator end() noexcept {
581 return _begin + size();
589 void plus_inplace_no_checks(RowViewCommon
const& x);
592 void operator+=(RowViewCommon
const& x);
595 [[nodiscard]] Row plus_no_checks(RowViewCommon
const& that)
const {
596 Row result(*
static_cast<Subclass const*
>(
this));
597 result.plus_inplace_no_checks(
static_cast<Subclass const&
>(that));
602 [[nodiscard]] Row operator+(RowViewCommon
const& x);
605 void operator+=(scalar_type a) {
606 for (
auto& x : *
this) {
607 x = plus_no_checks(x, a);
612 void operator*=(scalar_type a) {
613 for (
auto& x : *
this) {
614 x = product_no_checks(x, a);
619 [[nodiscard]] Row operator*(scalar_type a)
const {
620 Row result(*
static_cast<Subclass const*
>(
this));
625 template <
typename U>
626 [[nodiscard]]
bool operator==(U
const& that)
const {
628 return std::equal(begin(), end(), that.begin());
631 template <
typename U>
632 [[nodiscard]]
bool operator!=(U
const& that)
const {
633 return !(*
this == that);
636 template <
typename U>
637 [[nodiscard]]
bool operator<(U
const& that)
const {
639 cbegin(), cend(), that.cbegin(), that.cend());
642 template <
typename U>
643 [[nodiscard]]
bool operator>(U
const& that)
const {
647 void swap(RowViewCommon& that)
noexcept {
651 friend std::ostream& operator<<(std::ostream& os, RowViewCommon
const& x) {
652 os << detail::to_string(x);
657 explicit RowViewCommon(iterator first) : _begin(first) {}
663 template <
typename Mat,
typename Sub
class>
664 void throw_if_bad_dim(RowViewCommon<Mat, Subclass>
const& x,
665 RowViewCommon<Mat, Subclass>
const& y,
666 std::string_view arg_desc_x =
"the 1st argument",
667 std::string_view arg_desc_y =
"the 2nd argument");
670#include "matrix-common.tpp"
constexpr bool IsMatrix
Helper variable template.
Definition is-matrix.hpp:87
T lexicographical_compare(T... args)
void throw_if_not_square(Mat const &x, std::string_view arg_desc="the argument")
Throws if a matrix is not square.
void throw_if_bad_coords(Mat const &x, size_t r, size_t c)
Throws the arguments do not index an entry of a matrix.