// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // BoolMatrix.hpp // // ブール行列 ({0,1} 上の行列) // // 主な API: // BoolMatrix(rows, cols) — ゼロ行列 // BoolMatrix::identity(n) — 単位行列 // operator*, +, & — 行列積 (OR-AND), 和 (OR), AND // transitiveClosure() — 推移閉包 (Warshall) // reachability(from) — 到達可能頂点集合 // isReflexive, isSymmetric, isTransitive — 関係の性質 #ifndef CALX_LINALG_BOOL_MATRIX_HPP #define CALX_LINALG_BOOL_MATRIX_HPP #include #include #include #include namespace calx { /** * @brief ブール行列 (m × n, {0,1} 成分) */ class BoolMatrix { public: BoolMatrix(std::size_t rows, std::size_t cols) : rows_(rows), cols_(cols), data_(rows, std::vector(cols, false)) {} /// ビットベクトルから構築 BoolMatrix(std::size_t rows, std::size_t cols, const std::vector>& data) : rows_(rows), cols_(cols), data_(data) { data_.resize(rows); for (auto& row : data_) row.resize(cols, false); } static BoolMatrix identity(std::size_t n) { BoolMatrix m(n, n); for (std::size_t i = 0; i < n; ++i) m.data_[i][i] = true; return m; } std::size_t rows() const { return rows_; } std::size_t cols() const { return cols_; } bool get(std::size_t i, std::size_t j) const { return data_[i][j]; } void set(std::size_t i, std::size_t j, bool v) { data_[i][j] = v; } /// ブール行列積 (OR-AND): C[i][j] = OR_k (A[i][k] AND B[k][j]) friend BoolMatrix operator*(const BoolMatrix& a, const BoolMatrix& b) { if (a.cols_ != b.rows_) throw std::invalid_argument("BoolMatrix: dimension mismatch"); BoolMatrix c(a.rows_, b.cols_); for (std::size_t i = 0; i < a.rows_; ++i) for (std::size_t k = 0; k < a.cols_; ++k) if (a.data_[i][k]) for (std::size_t j = 0; j < b.cols_; ++j) if (b.data_[k][j]) c.data_[i][j] = true; return c; } /// OR (成分ごと) friend BoolMatrix operator|(const BoolMatrix& a, const BoolMatrix& b) { checkSameSize(a, b); BoolMatrix c(a.rows_, a.cols_); for (std::size_t i = 0; i < a.rows_; ++i) for (std::size_t j = 0; j < a.cols_; ++j) c.data_[i][j] = a.data_[i][j] || b.data_[i][j]; return c; } /// AND (成分ごと) friend BoolMatrix operator&(const BoolMatrix& a, const BoolMatrix& b) { checkSameSize(a, b); BoolMatrix c(a.rows_, a.cols_); for (std::size_t i = 0; i < a.rows_; ++i) for (std::size_t j = 0; j < a.cols_; ++j) c.data_[i][j] = a.data_[i][j] && b.data_[i][j]; return c; } /// 転置 BoolMatrix transpose() const { BoolMatrix t(cols_, rows_); for (std::size_t i = 0; i < rows_; ++i) for (std::size_t j = 0; j < cols_; ++j) t.data_[j][i] = data_[i][j]; return t; } /// 推移閉包 (Warshall のアルゴリズム) BoolMatrix transitiveClosure() const { if (rows_ != cols_) throw std::invalid_argument("BoolMatrix: transitive closure requires square matrix"); BoolMatrix t = *this; for (std::size_t k = 0; k < rows_; ++k) for (std::size_t i = 0; i < rows_; ++i) if (t.data_[i][k]) for (std::size_t j = 0; j < rows_; ++j) if (t.data_[k][j]) t.data_[i][j] = true; return t; } /// 頂点 from から到達可能な頂点集合 std::vector reachability(std::size_t from) const { if (rows_ != cols_) throw std::invalid_argument("BoolMatrix: reachability requires square matrix"); std::vector visited(rows_, false); std::vector stack = {from}; visited[from] = true; while (!stack.empty()) { auto v = stack.back(); stack.pop_back(); for (std::size_t j = 0; j < cols_; ++j) { if (data_[v][j] && !visited[j]) { visited[j] = true; stack.push_back(j); } } } return visited; } /// 反射的か (対角成分がすべて 1) bool isReflexive() const { if (rows_ != cols_) return false; for (std::size_t i = 0; i < rows_; ++i) if (!data_[i][i]) return false; return true; } /// 対称か bool isSymmetric() const { if (rows_ != cols_) return false; for (std::size_t i = 0; i < rows_; ++i) for (std::size_t j = i + 1; j < cols_; ++j) if (data_[i][j] != data_[j][i]) return false; return true; } /// 推移的か (A² ⊆ A) bool isTransitive() const { if (rows_ != cols_) return false; auto sq = *this * *this; for (std::size_t i = 0; i < rows_; ++i) for (std::size_t j = 0; j < cols_; ++j) if (sq.data_[i][j] && !data_[i][j]) return false; return true; } friend bool operator==(const BoolMatrix& a, const BoolMatrix& b) { if (a.rows_ != b.rows_ || a.cols_ != b.cols_) return false; return a.data_ == b.data_; } friend bool operator!=(const BoolMatrix& a, const BoolMatrix& b) { return !(a == b); } private: std::size_t rows_, cols_; std::vector> data_; static void checkSameSize(const BoolMatrix& a, const BoolMatrix& b) { if (a.rows_ != b.rows_ || a.cols_ != b.cols_) throw std::invalid_argument("BoolMatrix: size mismatch"); } }; } // namespace calx #endif // CALX_LINALG_BOOL_MATRIX_HPP