Skip to content

Instantly share code, notes, and snippets.

@leocelente
Created June 16, 2021 04:11
Show Gist options
  • Save leocelente/b81e99393fa3fb063dfbccf820dee4a2 to your computer and use it in GitHub Desktop.
Save leocelente/b81e99393fa3fb063dfbccf820dee4a2 to your computer and use it in GitHub Desktop.
Calculating matrix composition sizes in constexpr time and runtime. C++20 using TMP library brigand. https://godbolt.org/z/KEoWP8G3n
// https://godbolt.org/z/KEoWP8G3n
#include <fmt/core.h>
#include <array>
#include <brigand/algorithms.hpp>
#include <brigand/functions.hpp>
#include <brigand/sequences.hpp>
#include <brigand/types.hpp>
#include <numeric>
#include <tuple>
#include <vector>
using std::size_t;
namespace {
struct Break {
size_t rows = 0;
size_t cols = 0;
};
template <size_t R, size_t C>
struct Matrix {
size_t rows = R;
size_t cols = C;
constexpr Matrix() = default;
template <typename... Args>
constexpr Matrix(Args&&... args) {
auto co = [](auto&& x) { return x.cols; };
auto ro = [](auto&& x) { return x.rows; };
auto is_break = [co](auto const& x) { return x == co(Break{}); };
constexpr auto N = sizeof...(args);
const std::array<size_t const, N + 1> r = {ro(args)..., ro(Break{})};
const std::array<size_t const, N + 1> c = {co(args)..., co(Break{})};
size_t rows{}, cols{};
const size_t parts = std::count_if(c.cbegin(), c.cend(), is_break);
auto brk = c.begin();
auto brk_prev = brk;
for (size_t p = 0; p < parts; ++p) {
brk = std::find_if(brk_prev, c.cend(), is_break);
const size_t d_to_prev = std::distance(c.cbegin(), brk_prev);
const size_t d_to_brk = std::distance(c.cbegin(), ++brk);
rows += *std::max_element(&r[d_to_prev], &r[d_to_brk]);
cols = std::accumulate(brk_prev, brk, 0);
brk_prev = brk;
}
this->rows = rows;
this->cols = cols;
this->data.reserve(rows * cols);
}
std::vector<int> data{};
};
/****************************************************************************/
template <size_t N, size_t M>
struct FixedMatrix {
enum { rows = N, cols = M };
std::array<int, N * M> data{};
};
using NewLine = FixedMatrix<0, 0>;
constexpr static auto nl = NewLine{};
template <typename T>
using rows_of = brigand::int32_t<T::rows>;
template <typename T>
using cols_of = brigand::int32_t<T::cols>;
template <typename T>
using rows_all = brigand::transform<T, brigand::bind<rows_of, brigand::_1>>;
template <typename T>
using cols_all = brigand::transform<T, brigand::bind<cols_of, brigand::_1>>;
template <typename row>
struct Sizes {
using col_sizes =
brigand::transform<row, brigand::bind<cols_of, brigand::_1>>;
using row_sizes =
brigand::transform<row, brigand::bind<rows_of, brigand::_1>>;
using c = brigand::fold<col_sizes, brigand::int32_t<0>,
brigand::plus<brigand::_state, brigand::_element>>;
using r = brigand::fold<row_sizes, brigand::int32_t<0>,
brigand::max<brigand::_state, brigand::_element>>;
enum { cols = c::value };
enum { rows = r::value };
};
template <class... Ts>
struct MetaMatrix {
constexpr MetaMatrix(std::tuple<Ts...>) {}
using matrices = brigand::list<Ts..., NewLine>;
using list_rows = brigand::split<matrices, NewLine>;
using first_row = brigand::at_c<list_rows, 0>;
using list_sizes =
brigand::transform<list_rows, brigand::bind<Sizes, brigand::_1>>;
using cc = cols_all<list_sizes>;
using c = brigand::fold<cc, brigand::int32_t<0>,
brigand::max<brigand::_state, brigand::_element>>;
using rr = rows_all<list_sizes>;
using r = brigand::fold<rr, brigand::int32_t<0>,
brigand::plus<brigand::_state, brigand::_element>>;
enum { cols = c::value };
enum { rows = r::value };
std::array<int, r::value * c::value> data{};
};
/****************************************************************************/
void use_dynamic() {
Matrix<2, 1> B{};
Matrix<2, 2> A{B, B};
Matrix<1, 6> D{A, A};
auto C = Matrix<0, 0>{A, B, B, Break{}, //
B, A, B, Break{}, //
D};
fmt::print("C.rows = {} \nC.cols = {}\n", C.rows, C.cols);
}
void use_constexpr() {
FixedMatrix<2, 1> B{};
MetaMatrix A{std::make_tuple(B, B)};
MetaMatrix D{std::make_tuple(A, A)};
MetaMatrix C{std::make_tuple(A, B, B, nl, //
B, A, B, nl, //
D)}; // rows: 6, cols: 4
fmt::print("C.rows = {} \nC.cols = {}\n", C.rows, C.cols);
}
}; // namespace
int main(void) {
use_constexpr();
// use_dynamic();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment