16 #ifndef OPENKALMAN_CONCATENATE_HPP 17 #define OPENKALMAN_CONCATENATE_HPP 24 template<
typename T,
typename U, std::size_t...indices, std::size_t...I>
25 constexpr
bool concatenate_dimensions_match_impl(std::index_sequence<I...>)
27 return (([](std::size_t i){
return ((i != indices) and ...); }(I) or
32 template<
typename T,
typename U, std::size_t...indices>
34 concept concatenate_dimensions_match =
36 constexpr
bool concatenate_dimensions_match =
38 (concatenate_dimensions_match_impl<T, U, indices...>(std::make_index_sequence<index_count_v<T>> {}));
41 template<std::size_t I, std::size_t...indices,
typename DTup,
typename...DTups>
42 constexpr decltype(
auto) concatenate_vector_space_descriptor_impl(DTup&& d_tup, DTups&&...d_tups)
44 if constexpr (((I == indices) or ...))
46 auto f = [](
auto&& dtup){
47 if constexpr (I >= std::tuple_size_v<std::decay_t<decltype(dtup)>>) return coordinates::Axis {};
48 else return std::get<I>(std::forward<decltype(dtup)>(dtup));
50 return (f(std::forward<DTup>(d_tup)) + ... + f(std::forward<DTups>(d_tups)));
54 if constexpr (not (compares_with<std::tuple_element_t<I, DTup>, std::tuple_element_t<I, DTups>>and ...))
56 if (((std::get<I>(std::forward<DTup>(d_tup)) != std::get<I>(std::forward<DTups>(d_tups))) or ...))
57 throw std::invalid_argument {
"Arguments to concatenate do not match in at least index " + std::to_string(I)};
59 return std::get<I>(std::forward<DTup>(d_tup));
64 template<std::size_t...indices, std::size_t...I,
typename...DTups>
65 constexpr decltype(
auto) concatenate_vector_space_descriptor(
std::index_sequence<I...>, DTups&&...d_tups)
67 return std::tuple {concatenate_vector_space_descriptor_impl<I, indices...>(std::forward<DTups>(d_tups)...)...};
72 template<
typename T,
typename...Ts>
73 concept constant_concatenate_arguments =
74 (values::fixed<constant_coefficient<T>> and ... and values::fixed<constant_coefficient<Ts>>) and
77 template<
typename T,
typename = void,
typename...Ts>
80 template<
typename T,
typename...Ts>
82 std::enable_if_t<(values::internal::near(constant_coefficient<T>::value, constant_coefficient<Ts>::value) and ...)>, Ts...>
85 template<
typename T,
typename...Ts>
90 template<std::size_t
index, std::size_t...indices,
typename Args_tup, std::size_t...all_indices, std::size_t...pos>
91 constexpr
auto concatenate_diag_impl(Args_tup&& args_tup, std::index_sequence<all_indices...>, std::index_sequence<pos...>)
93 constexpr
auto p_index = std::get<index>(std::tuple{pos...});
94 if constexpr (((p_index == std::get<indices>(std::tuple{pos...})) and ...))
96 return std::get<p_index>(args_tup);
100 using Pattern = std::tuple_element_t<0, Args_tup>;
101 return make_zero<Pattern>(get_vector_space_descriptor<all_indices>(std::get<pos>(args_tup))...);
106 template<std::size_t...indices,
typename Ds_tup,
typename Args_tup, std::size_t...all_indices,
typename...Pos_seq>
107 constexpr
auto concatenate_diag(Ds_tup&& ds_tup, Args_tup&& args_tup, std::index_sequence<all_indices...> all_indices_seq, Pos_seq...pos_seq)
109 return tile(ds_tup, concatenate_diag_impl<indices...>(std::forward<Args_tup>(args_tup), all_indices_seq, pos_seq)...);
114 template<std::size_t...args_ix, std::size_t...pos>
115 constexpr
auto get_cat_indices(
116 std::index_sequence<>,
117 std::index_sequence<>,
118 std::index_sequence<args_ix...>,
119 std::index_sequence<pos...> pos_seq)
121 return std::tuple {pos_seq};
126 template<std::size_t ix, std::size_t...ixs, std::size_t...args_ix, std::size_t...pos>
127 constexpr
auto get_cat_indices(
128 std::index_sequence<ix, ixs...>,
129 std::index_sequence<> index_seq,
130 std::index_sequence<args_ix...> arg_ix_seq,
131 std::index_sequence<pos...>)
133 return get_cat_indices(
134 std::index_sequence<ixs...> {},
137 std::index_sequence<pos..., 0> {}
142 template<std::size_t ix, std::size_t...ixs, std::size_t
index, std::size_t...indices, std::size_t...args_ix, std::size_t...pos>
143 constexpr
auto get_cat_indices(
144 std::index_sequence<ix, ixs...> ix_seq,
145 std::index_sequence<index, indices...> index_seq,
146 std::index_sequence<args_ix...> arg_ix_seq,
147 std::index_sequence<pos...> pos_seq)
149 if constexpr (ix == index)
151 static_assert (((index != indices) and ...),
"No duplicate indices for concatenate function.");
152 return std::tuple_cat(get_cat_indices(
153 std::index_sequence<ixs...> {},
154 std::index_sequence<indices...> {},
156 std::index_sequence<pos..., args_ix> {})...);
158 else if constexpr (((ix == indices) or ...))
160 return get_cat_indices(
162 std::index_sequence<indices..., index> {},
168 return get_cat_indices(
169 std::index_sequence<ixs...> {},
172 std::index_sequence<pos..., 0> {});
190 #ifdef __cpp_concepts 191 template<std::size_t...indices,
indexible Arg, detail::concatenate_dimensions_match<Arg>...Args>
192 requires (
sizeof...(indices) > 0)
194 template<std::size_t...indices,
typename Arg,
typename...Args, std::enable_if_t<(
sizeof...(indices) > 0) and
195 (indexible<Arg> and ... and detail::concatenate_dimensions_match<Arg, Args>),
int> = 0>
197 constexpr decltype(
auto)
198 concatenate(Arg&& arg, Args&&...args)
200 auto seq = std::make_index_sequence<std::max({index_count_v<Arg>, index_count_v<Args>..., indices...})> {};
201 auto d_tup = detail::concatenate_vector_space_descriptor<indices...>(
204 if constexpr (
sizeof...(Args) == 0)
206 return std::forward<Arg>(arg);
208 else if constexpr ((zero<Arg> and ... and zero<Args>))
210 return std::apply([](
auto&&...ds){
return make_zero<Arg>(std::forward<decltype(ds)>(ds)...); }, d_tup);
212 else if constexpr (
sizeof...(indices) == 1 and detail::constant_concatenate_arguments<Arg, Args...>)
214 return std::apply([](
auto&&...ds){
218 else if constexpr (
sizeof...(indices) == 2 and ((indices == 0) or ...) and ((indices == 1) or ...) and
219 (diagonal_matrix<Args> and ...))
223 else if constexpr (
sizeof...(indices) == 2 and ((indices == 0) or ...) and ((indices == 1) or ...) and
224 (triangle_type_of_v<Arg, Args...> !=
TriangleType::any) and (square_shaped<Arg> and ... and square_shaped<Args>))
226 return make_triangular_matrix<triangle_type_of_v<Arg>>(
229 else if constexpr (
sizeof...(indices) == 2 and ((indices == 0) or ...) and ((indices == 1) or ...) and
230 (hermitian_matrix<Arg> and ... and hermitian_matrix<Args>))
232 constexpr
auto t = hermitian_adapter_type_of_v<Arg>;
233 auto maybe_transpose = [](
auto&& m) {
234 using M = decltype(m);
235 if constexpr(t == hermitian_adapter_type_of_v<M>)
return nested_object(std::forward<M>(m));
238 return make_hermitian_matrix<t>(
241 else if constexpr (
sizeof...(indices) == 1)
243 return tile(d_tup, std::forward<Arg>(arg), std::forward<Args>(args)...);
247 auto pos_tup = detail::get_cat_indices(seq, std::index_sequence<indices...> {},
248 std::make_index_sequence<1 +
sizeof...(Args)> {}, std::index_sequence<> {});
250 return std::apply([&](
auto...pos_seq){
251 return detail::concatenate_diag<indices...>(d_tup,
252 std::forward_as_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...), seq, pos_seq...);
260 #endif //OPENKALMAN_CONCATENATE_HPP constexpr bool dimension_size_of_index_is
Specifies that a given index of T has a specified size.
Definition: dimension_size_of_index_is.hpp:44
decltype(auto) constexpr tile(const std::tuple< Ds... > &ds_tuple, Block &&block, Blocks &&...blocks)
Create a matrix or tensor by tiling individual blocks.
Definition: tile.hpp:111
Lower, upper, or diagonal matrix.
constexpr bool indexible
T is a generalized tensor type.
Definition: indexible.hpp:32
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
decltype(auto) constexpr to_diagonal(Arg &&arg)
Convert an indexible object into a diagonal matrix.
Definition: to_diagonal.hpp:32
The constant associated with T, assuming T is a constant_matrix.
Definition: constant_coefficient.hpp:36
decltype(auto) constexpr transpose(Arg &&arg)
Take the transpose of a matrix.
Definition: transpose.hpp:58
decltype(auto) constexpr all_vector_space_descriptors(const T &t)
Return a collection of coordinates::pattern objects associated with T.
Definition: all_vector_space_descriptors.hpp:52
The root namespace for OpenKalman.
Definition: basics.hpp:34
The concept, trait, or restraint is permitted, but whether it applies is not necessarily known at com...
decltype(auto) constexpr diagonal_of(Arg &&arg)
Extract a column vector (or column slice for rank>2 tensors) comprising the diagonal elements...
Definition: diagonal_of.hpp:33
constexpr bool near(const Arg1 &arg1, const Arg2 &arg2)
Determine whether two numbers are within a rounding tolerance.
Definition: near.hpp:36
decltype(auto) constexpr nested_object(Arg &&arg)
Retrieve a nested object of Arg, if it exists.
Definition: nested_object.hpp:34
decltype(auto) constexpr concatenate_diagonal(V &&v, Vs &&... vs)
Concatenate one or more typed matrices diagonally.
Definition: typed-matrix-overloads.hpp:340
Definition: concatenate.hpp:78
constexpr bool index
An object describing a collection of /ref values::index objects.
Definition: index.hpp:75