Created
June 16, 2021 04:11
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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