16 #ifndef OPENKALMAN_CHIPWISE_OPERATION_HPP 17 #define OPENKALMAN_CHIPWISE_OPERATION_HPP 25 template<std::
size_t ix,
typename Best_d>
26 const Best_d& chipwise_vector_space_descriptor_for(
const Best_d& best_d) {
return best_d; }
28 template<std::size_t ix,
typename Best_d,
typename Arg,
typename...Args>
29 decltype(
auto) chipwise_vector_space_descriptor_for(const Best_d& best_d, const Arg& arg, const Args&...args)
31 auto d = get_vector_space_descriptor<ix>(arg);
32 using D = decltype(d);
33 if constexpr (fixed_pattern<Best_d>)
35 if constexpr (fixed_pattern<D>)
36 static_assert(coordinates::dimension_of_v<D> == coordinates::dimension_of_v<Best_d>,
37 "Arguments to chipwise_operation must have matching vector space descriptors.");
39 if (d != best_d)
throw std::invalid_argument {
"Arguments to chipwise_operation must have matching vector space descriptors."};
40 return chipwise_vector_space_descriptor_for<ix>(best_d, args...);
44 if (d != best_d)
throw std::invalid_argument {
"Arguments to chipwise_operation must have matching vector space descriptors."};
45 if constexpr (fixed_pattern<D>)
46 return chipwise_vector_space_descriptor_for<ix>(d, args...);
48 return chipwise_vector_space_descriptor_for<ix>(best_d, args...);
54 template<std::size_t...ix,
typename Arg,
typename...Args>
55 auto make_chipwise_default(std::index_sequence<ix...>,
const Arg& arg,
const Args&...args)
57 return make_dense_object<Arg>(chipwise_vector_space_descriptor_for<ix>(get_vector_space_descriptor<ix>(arg), args...)...);
62 template<
bool uses_indices, std::size_t...indices, std::size_t...indices_ix,
63 typename Ix_tup,
typename M,
typename Op,
typename...Args>
65 chipwise_op_chip(std::index_sequence<indices...>, std::index_sequence<indices_ix...>,
const Ix_tup& ix_tup,
66 M& m,
const Op& op, Args&&...args)
68 if constexpr (uses_indices)
70 auto chip = op(get_chip<indices...>(std::forward<Args>(args), std::get<indices_ix>(ix_tup)...)..., std::get<indices_ix>(ix_tup)...);
71 set_chip<indices...>(m, std::move(chip), std::get<indices_ix>(ix_tup)...);
75 auto chip = op(get_chip<indices...>(std::forward<Args>(args), std::get<indices_ix>(ix_tup)...)...);
76 set_chip<indices...>(m, std::move(chip), std::get<indices_ix>(ix_tup)...);
82 template<
bool uses_indices,
typename Indices,
typename Ix_tup,
typename M,
typename Op,
typename...Args>
84 chipwise_op(Indices indices,
const Ix_tup& ix_tup, M& m,
const Op& op, Args&&...args)
87 static_assert(std::tuple_size_v<Ix_tup> == num_indices);
88 std::make_index_sequence<num_indices> indices_seq;
89 chipwise_op_chip<uses_indices>(indices, indices_seq, ix_tup, m, op, std::forward<Args>(args)...);
92 template<
bool uses_indices, std::size_t
index, std::size_t...indices,
93 typename Indices_seq,
typename Ix_tup,
typename M,
typename Op,
typename...Args>
95 chipwise_op(Indices_seq indices_seq,
const Ix_tup& ix_tup, M& m,
const Op& op, Args&&...args)
97 for (std::size_t i = 0; i < get_index_dimension_of<index>(m); ++i)
98 chipwise_op<uses_indices, indices...>(indices_seq, std::tuple_cat(ix_tup, std::tuple{i}), m, op, args...);
120 #ifdef __cpp_concepts 121 template<std::size_t...indices,
typename Operation,
indexible...Args> requires (
sizeof...(Args) > 0)
123 template<std::size_t...indices,
typename Operation,
typename...Args, std::enable_if_t<
124 (indexible<Args> and ...) and (sizeof...(Args) > 0),
int> = 0>
129 if constexpr (
sizeof...(indices) > 0)
131 auto m = detail::make_chipwise_default(std::make_index_sequence<std::max({index_count_v<Args>...})>{}, args...);
133 constexpr
bool uses_indices = std::is_invocable_v<Operation,
134 decltype(get_chip<indices...>(std::declval<Args>(), std::integral_constant<decltype(indices), 0>{}...))...,
135 std::integral_constant<decltype(indices), 0>...>;
137 std::index_sequence<indices...> indices_seq;
138 detail::chipwise_op<uses_indices, indices...>(indices_seq, std::tuple{}, m,
operation, std::forward<Args>(args)...);
143 return operation(std::forward<Args>(args)...);
150 template<std::
size_t op_ix,
typename OpResult>
151 auto nullary_chipwise_vector_space_descriptor(
const OpResult& op_result)
153 return get_vector_space_descriptor<op_ix>(op_result);
156 template<std::size_t op_ix, std::size_t
index, std::size_t...indices,
typename OpResult,
typename I,
typename...Is>
157 auto nullary_chipwise_vector_space_descriptor(
const OpResult& op_result, I i, Is...is)
159 if constexpr (op_ix == index)
return get_vector_space_descriptor<op_ix>(op_result) * i;
160 else return nullary_chipwise_vector_space_descriptor<op_ix, indices...>(op_result, is...);
163 template<std::size_t...indices, std::size_t...op_ix,
typename OpResult,
typename...Is>
164 auto make_nullary_chipwise_default(std::index_sequence<op_ix...>,
const OpResult& op_result, Is...is)
166 return make_dense_object<OpResult>(nullary_chipwise_vector_space_descriptor<op_ix, indices...>(op_result, is...)...);
170 template<
bool uses_indices, std::size_t...indices, std::size_t...index_ixs,
171 typename Ix_tup,
typename M,
typename Op,
typename...Args>
173 nullary_chipwise_op_chip(std::index_sequence<indices...>, std::index_sequence<index_ixs...>,
const Ix_tup& ix_tup,
176 [](M& m,
const Op& op,
auto...ix){
177 if constexpr (uses_indices)
178 set_chip<indices...>(m, op(ix...), ix...);
180 set_chip<indices...>(m, op(), ix...);
181 }(m, op, std::get<index_ixs>(ix_tup)...);
184 template<
bool uses_indices,
bool first,
typename All_index_seq,
typename Ix_tup,
typename M,
typename Op>
186 nullary_chipwise_op(All_index_seq all_index_seq,
const Ix_tup& ix_tup, M& m,
const Op& op)
188 if constexpr (not first)
190 std::make_index_sequence<std::tuple_size_v<Ix_tup>> index_ix_seq;
191 nullary_chipwise_op_chip<uses_indices>(all_index_seq, index_ix_seq, ix_tup, m, op);
195 template<
bool uses_indices,
bool first, std::size_t
index, std::size_t...indices,
typename All_index_seq,
196 typename Ix_tup,
typename M,
typename Op,
typename I,
typename...Is>
198 nullary_chipwise_op(All_index_seq all_index_seq,
const Ix_tup& ix_tup, M& m,
const Op& op, I i, Is...is)
202 auto new_ix_tup = std::tuple_cat(ix_tup, std::tuple{std::integral_constant<std::size_t, 0> {}});
203 nullary_chipwise_op<uses_indices,
true, indices...>(all_index_seq, new_ix_tup, m, op, is...);
205 constexpr std::size_t begin = first ? 1 : 0;
207 for (std::size_t j = begin; j < static_cast<std::size_t>(i); ++j)
209 auto new_ix_tup = std::tuple_cat(ix_tup, std::tuple{j});
210 nullary_chipwise_op<uses_indices,
false, indices...>(all_index_seq, new_ix_tup, m, op, is...);
225 #ifdef __cpp_concepts 226 template<std::size_t...indices,
typename Operation,
values::index...Is> requires (
sizeof...(Is) ==
sizeof...(indices))
228 template<std::size_t...indices,
typename Operation,
typename...Is, std::enable_if_t<
229 (values::index<Is> and ...) and (
sizeof...(Is) ==
sizeof...(indices)),
int> = 0>
234 constexpr
bool uses_indices = std::is_invocable_v<Operation, std::integral_constant<decltype(indices), 0>...>;
236 auto op_result = [](
const Operation&
operation){
237 if constexpr (uses_indices)
return operation(std::integral_constant<decltype(indices), 0> {}...);
240 using OpResult = decltype(op_result);
242 static_assert((dimension_size_of_index_is<OpResult, indices, 1, Applicability::permitted> and ...),
243 "Operator must return a chip, meaning that the dimension is 1 for each of the specified indices.");
246 constexpr std::size_t num_result_indices = std::max({index_count_v<OpResult>, (indices + 1)...});
247 auto m = detail::make_nullary_chipwise_default<indices...>(std::make_index_sequence<num_result_indices>{}, op_result, is...);
248 set_chip<indices...>(m, std::move(op_result), std::integral_constant<decltype(indices), 0> {}...);
250 detail::nullary_chipwise_op<uses_indices,
true, indices...>(std::index_sequence<indices...> {}, std::tuple{}, m,
operation, is...);
257 #endif //OPENKALMAN_CHIPWISE_OPERATION_HPP constexpr bool indexible
T is a generalized tensor type.
Definition: indexible.hpp:32
constexpr auto chipwise_operation(const Operation &operation, Args &&...args)
Perform a chipwise n-ary operation (n>0) on one or more indexible objects.
Definition: chipwise_operation.hpp:127
The root namespace for OpenKalman.
Definition: basics.hpp:34
constexpr bool size
T is either an index representing a size, or void which represents that there is no size...
Definition: size.hpp:32
constexpr bool index
T is an index value.
Definition: index.hpp:56
constexpr Arg && set_chip(Arg &&arg, Chip &&chip, Ixs...ixs)
Set a sub-array having rank less than the rank of the input object.
Definition: set_chip.hpp:64
operation(const Operation &, const Args &...) -> operation< Operation, Args... >
Deduction guide.
constexpr bool index
An object describing a collection of /ref values::index objects.
Definition: index.hpp:75