1111#define XTENSOR_OPERATION_HPP
1212
1313#include < algorithm>
14+ #include < array>
1415#include < type_traits>
1516
1617#include < xtl/xsequence.hpp>
@@ -148,6 +149,7 @@ namespace xt
148149 struct functor
149150 {
150151 using result_type = R;
152+ using cast_result_type = R;
151153
152154 template <class A1 >
153155 constexpr result_type operator ()(const A1 & arg) const
@@ -167,6 +169,117 @@ namespace xt
167169 };
168170 };
169171
172+ template <class E , class = void >
173+ struct cast_expression : std::false_type
174+ {
175+ };
176+
177+ template <class F , class CT >
178+ struct cast_expression <xfunction<F, CT >, std::void_t <typename F::cast_result_type>> : std::true_type
179+ {
180+ using result_type = typename F::cast_result_type;
181+ };
182+
183+ template <class E >
184+ struct permutation_view : std::false_type
185+ {
186+ };
187+
188+ template <class CT , class S , layout_type L, class FST >
189+ struct permutation_view <xstrided_view<CT , S, L, FST >>
190+ : std::bool_constant<
191+ L == layout_type::dynamic && is_specialization_of<inner_storage_getter, FST >::value>
192+ {
193+ };
194+
195+ template <std::size_t A, std::size_t B, std::size_t C, class E1 , class V , class R , class S >
196+ inline void run_permutation_assign (E1 & dst, const V& src, S scale)
197+ {
198+ const std::size_t shape_a = src.shape ()[A];
199+ const std::size_t shape_b = src.shape ()[B];
200+ const std::size_t shape_c = src.shape ()[C];
201+ const std::size_t src_stride_a = static_cast <std::size_t >(src.strides ()[A]);
202+ const std::size_t src_stride_b = static_cast <std::size_t >(src.strides ()[B]);
203+ const std::size_t src_stride_c = static_cast <std::size_t >(src.strides ()[C]);
204+ const std::size_t dst_stride_a = static_cast <std::size_t >(dst.strides ()[A]);
205+ const std::size_t dst_stride_b = static_cast <std::size_t >(dst.strides ()[B]);
206+ const std::size_t dst_stride_c = static_cast <std::size_t >(dst.strides ()[C]);
207+ auto * src_data = src.data () + src.data_offset ();
208+ auto * dst_data = dst.data () + dst.data_offset ();
209+ if (
210+ shape_c == 3 && src_stride_c == 1 && src_stride_b == 3 && src_stride_a == shape_b * 3
211+ && dst_stride_b == 1 && dst_stride_a == shape_b && dst_stride_c == shape_a * shape_b)
212+ {
213+ const std::size_t plane_size = shape_a * shape_b;
214+ auto * dst_0 = dst_data;
215+ auto * dst_1 = dst_data + plane_size;
216+ auto * dst_2 = dst_data + 2 * plane_size;
217+ for (std::size_t i = 0 ; i < plane_size; ++i)
218+ {
219+ dst_0[i] = static_cast <R>(src_data[3 * i]) / static_cast <R>(scale);
220+ dst_1[i] = static_cast <R>(src_data[3 * i + 1 ]) / static_cast <R>(scale);
221+ dst_2[i] = static_cast <R>(src_data[3 * i + 2 ]) / static_cast <R>(scale);
222+ }
223+ return ;
224+ }
225+ constexpr std::size_t tile_size = 32 ;
226+ for (std::size_t a0 = 0 ; a0 < shape_a; a0 += tile_size)
227+ {
228+ for (std::size_t b0 = 0 ; b0 < shape_b; b0 += tile_size)
229+ {
230+ const std::size_t a_end = std::min (a0 + tile_size, shape_a);
231+ const std::size_t b_end = std::min (b0 + tile_size, shape_b);
232+ for (std::size_t a = a0; a < a_end; ++a)
233+ {
234+ for (std::size_t b = b0; b < b_end; ++b)
235+ {
236+ for (std::size_t c = 0 ; c < shape_c; ++c)
237+ {
238+ const auto src_offset = a * src_stride_a + b * src_stride_b + c * src_stride_c;
239+ const auto dst_offset = a * dst_stride_a + b * dst_stride_b + c * dst_stride_c;
240+ dst_data[dst_offset] = static_cast <R>(src_data[src_offset]) / static_cast <R>(scale);
241+ }
242+ }
243+ }
244+ }
245+ }
246+ }
247+
248+ template <class E1 , class V , class R , class S >
249+ inline bool try_3d_permutation_assign (E1 & dst, const V& src, S scale)
250+ {
251+ if (dst.dimension () != 3 || src.dimension () != 3 || dst.shape () != src.shape ()
252+ || !dst.is_contiguous () || dst.layout () != layout_type::row_major)
253+ {
254+ return false ;
255+ }
256+
257+ std::array<std::size_t , 3 > axes = {0 , 1 , 2 };
258+ std::sort (axes.begin (), axes.end (), [&](auto lhs, auto rhs) { return src.strides ()[lhs] > src.strides ()[rhs]; });
259+ if (src.strides ()[axes[2 ]] != 1
260+ || static_cast <std::size_t >(src.strides ()[axes[1 ]]) != src.shape ()[axes[2 ]]
261+ || static_cast <std::size_t >(src.strides ()[axes[0 ]])
262+ != src.shape ()[axes[2 ]] * src.shape ()[axes[1 ]])
263+ {
264+ return false ;
265+ }
266+
267+ #define XTENSOR_RUN_PERMUTATION (A, B, C ) \
268+ if (axes == std::array<std::size_t , 3 >{A, B, C}) \
269+ { \
270+ run_permutation_assign<A, B, C, E1 , V, R>(dst, src, scale); \
271+ return true ; \
272+ }
273+ XTENSOR_RUN_PERMUTATION (0 , 1 , 2 )
274+ XTENSOR_RUN_PERMUTATION (0 , 2 , 1 )
275+ XTENSOR_RUN_PERMUTATION (1 , 0 , 2 )
276+ XTENSOR_RUN_PERMUTATION (1 , 2 , 0 )
277+ XTENSOR_RUN_PERMUTATION (2 , 0 , 1 )
278+ XTENSOR_RUN_PERMUTATION (2 , 1 , 0 )
279+ #undef XTENSOR_RUN_PERMUTATION
280+ return false ;
281+ }
282+
170283 template <class Tag , class F , class ... E>
171284 struct select_xfunction_expression ;
172285
@@ -211,6 +324,31 @@ namespace xt
211324 enable_if_t <has_xexpression<std::decay_t <E>...>::value, xfunction_type<F, E...>>::type;
212325 }
213326
327+ template <class E1 , class CT1 , class CT2 >
328+ inline bool try_permutation_assign (E1 & dst, const xfunction<detail::divides, CT1 , CT2 >& expression)
329+ {
330+ using cast_expression_type = std::decay_t <decltype (std::get<0 >(expression.arguments ()))>;
331+ if constexpr (detail::cast_expression<cast_expression_type>::value && is_xscalar<std::decay_t <CT2 >>::value)
332+ {
333+ const auto & cast_expression = std::get<0 >(expression.arguments ());
334+ const auto & view = std::get<0 >(cast_expression.arguments ());
335+ using view_type = std::decay_t <decltype (view)>;
336+ using cast_result_type = typename detail::cast_expression<cast_expression_type>::result_type;
337+ if constexpr (
338+ detail::permutation_view<view_type>::value
339+ && std::is_same<cast_result_type, typename E1 ::value_type>::value
340+ && std::is_floating_point<cast_result_type>::value)
341+ {
342+ return detail::try_3d_permutation_assign<E1 , view_type, cast_result_type>(
343+ dst,
344+ view,
345+ std::get<1 >(expression.arguments ())()
346+ );
347+ }
348+ }
349+ return false ;
350+ }
351+
214352#undef UNARY_OPERATOR_FUNCTOR
215353#undef BINARY_OPERATOR_FUNCTOR
216354
0 commit comments