tensor_adaptor.hpp Source File

tensor_adaptor.hpp Source File#

Composable Kernel: tensor_adaptor.hpp Source File
tensor_description/tensor_adaptor.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2018-2023, Advanced Micro Devices, Inc. All rights reserved.
3
4#pragma once
5
9
10namespace ck {
11
12// Transforms: Tuple<transforms...>
13// LowerDimensionHiddenIdss : Tuple<Sequence<...>, ...>
14// UpperDimensionHiddenIdss : Tuple<Sequence<...>, ...>
15// BottomDimensionHiddenIds : Sequence<...>
16// TopDimensionHiddenIds : Sequence<...>
17template <typename Transforms,
18 typename LowerDimensionHiddenIdss,
19 typename UpperDimensionHiddenIdss,
20 typename BottomDimensionHiddenIds,
21 typename TopDimensionHiddenIds>
23{
24 __host__ __device__ static constexpr index_t GetNumOfTransform() { return Transforms::Size(); }
25
26 __host__ __device__ constexpr const auto& GetTransforms() const { return transforms_; }
27
28 __host__ __device__ static constexpr auto GetLowerDimensionHiddenIdss()
29 {
30 return LowerDimensionHiddenIdss{};
31 }
32
33 __host__ __device__ static constexpr auto GetUpperDimensionHiddenIdss()
34 {
35 return UpperDimensionHiddenIdss{};
36 }
37
38 __host__ __device__ static constexpr auto GetTopDimensionHiddenIds()
39 {
40 return TopDimensionHiddenIds{};
41 }
42
43 __host__ __device__ static constexpr auto GetBottomDimensionHiddenIds()
44 {
45 return BottomDimensionHiddenIds{};
46 }
47
48 __host__ __device__ static constexpr auto InitializeElementSize(const Transforms& transforms)
49 {
50 const auto lengths = generate_tuple(
51 [&](auto idim_top) {
52 constexpr auto tmp = GetTransformAndItsUpperDimension(idim_top);
53
54 constexpr index_t itran = tmp[Number<0>{}];
55 constexpr index_t idim_up = tmp[Number<1>{}];
56 constexpr bool found = tmp[Number<2>{}];
57
58 static_assert(found == true,
59 "wrong! not found matching transformation and upper-dimension");
60
61 const auto length =
62 transforms[Number<itran>{}].GetUpperLengths()[Number<idim_up>{}];
63
64 return length;
65 },
67
68 // TODO: make container_reduce support tuple of Number and index_t
69 return container_reduce(lengths, math::multiplies{}, Number<1>{});
70 }
71
72 template <index_t IDim>
73 __host__ __device__ static constexpr auto GetTransformAndItsUpperDimension(Number<IDim>)
74 {
75 constexpr auto idim_top = Number<IDim>{};
76
77 constexpr index_t idim_hidden = TopDimensionHiddenIds::At(idim_top);
78
79 index_t itran_found = 0;
80 index_t idim_up_found = 0;
81 bool found = false;
82
83 static_for<0, ntransform_, 1>{}([&](auto itran) {
84 constexpr auto up_dim_ids = UpperDimensionHiddenIdss{}[itran];
85
86 static_for<0, up_dim_ids.Size(), 1>{}([&](auto idim_up) {
87 if constexpr(up_dim_ids[idim_up] == idim_hidden)
88 {
89 itran_found = itran;
90 idim_up_found = idim_up;
91 found = true;
92 }
93 });
94 });
95
96 return make_tuple(itran_found, idim_up_found, found);
97 }
98
99 __host__ __device__ static constexpr index_t GetNumOfBottomDimension()
100 {
101 return BottomDimensionHiddenIds::Size();
102 }
103
104 __host__ __device__ static constexpr index_t GetNumOfTopDimension()
105 {
106 return TopDimensionHiddenIds::Size();
107 }
108
109 __host__ __device__ static constexpr index_t GetNumOfHiddenDimension()
110 {
111 constexpr auto all_low_dim_ids =
112 unpack([](auto&&... xs) constexpr { return merge_sequences(xs...); },
113 LowerDimensionHiddenIdss{});
114
115 constexpr auto all_up_dim_ids =
116 unpack([](auto&&... xs) constexpr { return merge_sequences(xs...); },
117 UpperDimensionHiddenIdss{});
118
119 constexpr auto all_dim_ids = merge_sequences(all_low_dim_ids, all_up_dim_ids);
120
121 using unique_sort_all_dim_ids = typename sequence_unique_sort<decltype(all_dim_ids),
124
125 return unique_sort_all_dim_ids::Size();
126 }
127
132
136
137 // may be index_t or Number<>
138 using ElementSize = remove_cv_t<decltype(InitializeElementSize(Transforms{}))>;
139
140 public:
141#if 0 // workaround compiler complaint about constexpr
142 __host__ __device__ constexpr TensorAdaptor() = default;
143#else
144 __host__ __device__ constexpr TensorAdaptor() : transforms_{}, element_size_{} {}
145#endif
146
147 __host__ __device__ constexpr TensorAdaptor(const Transforms& transforms)
148 : transforms_{transforms}, element_size_{InitializeElementSize(transforms)}
149 {
150 static_assert(Transforms::Size() == ntransform_ &&
151 LowerDimensionHiddenIdss::Size() == ntransform_ &&
152 UpperDimensionHiddenIdss::Size() == ntransform_,
153 "wrong! inconsistent # of transformations");
154
155 // TODO check dependency of dimensions is valid
156 }
157
158 __host__ __device__ constexpr auto GetElementSize() const { return element_size_; }
159
160#if 0 // debug
161 template <index_t I>
162 __host__ __device__ constexpr index_t GetTopDimensionLength(Number<I> idim) const
163 {
164 // TODO: not implemented
165 }
166
167 template <index_t I>
168 __host__ __device__ constexpr index_t GetBottomDimensionLength(Number<I> idim) const
169 {
170 // TODO: not implemented
171 }
172#endif
173
174 template <typename TopIdx>
175 __host__ __device__ constexpr auto CalculateBottomIndex(const TopIdx& idx_top) const
176 {
177 static_assert(TopIdx::Size() == TopDimensionHiddenIds::Size(),
178 "wrong! # of dimension inconsistent");
179
180 constexpr index_t ntransform = GetNumOfTransform();
181 constexpr index_t ndim_hidden = GetNumOfHiddenDimension();
182
183 MultiIndex<ndim_hidden> idx_hidden;
184
185 // initialize uppest index
186 set_container_subset(idx_hidden, GetTopDimensionHiddenIds(), idx_top);
187
188 // calculate hidden index
189 static_for<ntransform, 0, -1>{}([&](auto itran_p1) {
190 auto itran = itran_p1 - Number<1>{};
191 const auto& tran = GetTransforms().At(itran);
192 constexpr auto dims_low = GetLowerDimensionHiddenIdss().At(itran);
193 constexpr auto dims_up = GetUpperDimensionHiddenIdss().At(itran);
194
195 const auto idx_up = get_container_subset(idx_hidden, dims_up);
196
197 MultiIndex<dims_low.Size()> idx_low;
198
199 tran.CalculateLowerIndex(idx_low, idx_up);
200
201 set_container_subset(idx_hidden, dims_low, idx_low);
202 });
203
204 return get_container_subset(idx_hidden, BottomDimensionHiddenIds{});
205 }
206
207 __host__ __device__ static constexpr bool IsKnownAtCompileTime()
208 {
209 bool is_known = true;
210
211 static_for<0, Transforms::Size(), 1>{}([&](auto i) {
212 is_known &= remove_cvref_t<decltype(Transforms{}[i])>::IsKnownAtCompileTime();
213 });
214
216 }
217
218 __host__ __device__ void Print() const
219 {
220 printf("{");
221 printf("TensorAdaptor, ");
222 static_for<0, ntransform_, 1>{}([&](auto i) {
223 printf("transforms: ");
224 transforms_[i].Print();
225 printf("LowerDimensionHiddenIds:");
226 LowerDimensionHiddenIdss{}.At(i).Print();
227 printf("UpperDimensionHiddenIds:");
228 UpperDimensionHiddenIdss{}.At(i).Print();
229 });
230
231 printf("BottomDimensionHiddenIds:");
232 BottomDimensionHiddenIds::Print();
233 printf("TopDimensionHiddenIds:");
234 TopDimensionHiddenIds::Print();
235
236 printf("}");
237 }
238
239 private:
240 Transforms transforms_;
241 ElementSize element_size_;
242};
243
244template <typename TensorAdaptor0, typename TensorAdaptor1>
245__host__ __device__ constexpr auto chain_tensor_adaptors(const TensorAdaptor0& adaptor0,
246 const TensorAdaptor1& adaptor1)
247{
248 static_assert(TensorAdaptor0::GetNumOfTopDimension() ==
249 TensorAdaptor1::GetNumOfBottomDimension(),
250 "wrong!");
251
252 // all_transforms = transform0 + transform1
253 const auto all_transforms =
254 container_concat(adaptor0.GetTransforms(), adaptor1.GetTransforms());
255
256 // shift
257 constexpr index_t adaptor0_max_hidden_id = [&]() {
258 index_t adaptor0_max_hidden_id_ = NumericLimits<index_t>::Min();
259
260 static_for<0, TensorAdaptor0::GetNumOfTransform(), 1>{}([&](auto itran) {
261 constexpr index_t ndim_low =
262 TensorAdaptor0{}.GetTransforms()[itran].GetNumOfLowerDimension();
263
264 static_for<0, ndim_low, 1>{}([&](auto idim_low) {
265 adaptor0_max_hidden_id_ =
266 math::max(adaptor0_max_hidden_id_,
267 TensorAdaptor0::GetLowerDimensionHiddenIdss()[itran][idim_low].value);
268 });
269
270 constexpr index_t ndim_up =
271 TensorAdaptor0{}.GetTransforms()[itran].GetNumOfUpperDimension();
272
273 static_for<0, ndim_up, 1>{}([&](auto idim_up) {
274 adaptor0_max_hidden_id_ =
275 math::max(adaptor0_max_hidden_id_,
276 TensorAdaptor0::GetUpperDimensionHiddenIdss()[itran][idim_up].value);
277 });
278 });
279
280 return adaptor0_max_hidden_id_;
281 }();
282
283 constexpr index_t adaptor1_min_hidden_id = [&]() {
284 index_t adaptor1_min_hidden_id_ = NumericLimits<index_t>::Max();
285
286 static_for<0, TensorAdaptor1::GetNumOfTransform(), 1>{}([&](auto itran) {
287 constexpr index_t ndim_low =
288 TensorAdaptor1{}.GetTransforms()[itran].GetNumOfLowerDimension();
289
290 // get the min of all lower dimenions, but not bottom dimension (because their id will
291 // be matched with top id from adaptor0)
292 static_for<0, ndim_low, 1>{}([&](auto idim_low) {
293 constexpr index_t low_dim_hidden_id =
294 TensorAdaptor1::GetLowerDimensionHiddenIdss()[itran][idim_low].value;
295
296 bool is_bottom_dim = false;
297 static_for<0, TensorAdaptor1::GetNumOfBottomDimension(), 1>{}([&](auto i) {
298 if constexpr(low_dim_hidden_id ==
299 TensorAdaptor1::GetBottomDimensionHiddenIds()[i])
300 {
301 is_bottom_dim = true;
302 }
303 });
304
305 if(!is_bottom_dim)
306 {
307 adaptor1_min_hidden_id_ = math::min(adaptor1_min_hidden_id_, low_dim_hidden_id);
308 }
309 });
310
311 constexpr index_t ndim_up =
312 TensorAdaptor1{}.GetTransforms()[itran].GetNumOfUpperDimension();
313
314 // get the min of all upper dimensions
315 static_for<0, ndim_up, 1>{}([&](auto idim_up) {
316 adaptor1_min_hidden_id_ =
317 math::min(adaptor1_min_hidden_id_,
318 TensorAdaptor1::GetUpperDimensionHiddenIdss()[itran][idim_up].value);
319 });
320 });
321
322 return adaptor1_min_hidden_id_;
323 }();
324
325 constexpr index_t adaptor1_hidden_id_shift =
326 adaptor0_max_hidden_id + 1 - adaptor1_min_hidden_id;
327
328 constexpr index_t ndim_bottom_1 = TensorAdaptor1::GetNumOfBottomDimension();
329
330 // all_low_dim_hidden_idss =
331 // low_dim_hidden_idss_0 + match_hidden_id_for_1(shift_hidden_id_for_1(low_dim_hiden_idss_1))
332 constexpr auto low_dim_hidden_idss_1 = generate_tuple(
333 // generate sequence of ids for a transform
334 [&](auto itran) {
335 constexpr auto ndim_low_1 = TensorAdaptor1::GetLowerDimensionHiddenIdss()[itran].Size();
336
337 constexpr auto low_dim_hidden_ids_1 =
338 TensorAdaptor1::GetLowerDimensionHiddenIdss()[itran];
339
340 // sequence in, sequence out
341 constexpr auto low_dim_hidden_ids_1_mod = [&]() constexpr {
342 auto low_dim_hidden_ids_1_mod_ = to_multi_index(low_dim_hidden_ids_1);
343
344 // shift hidden id so every dim id is unique
345 static_for<0, ndim_low_1, 1>{}([&](auto idim_low_1) {
346 low_dim_hidden_ids_1_mod_(idim_low_1) += adaptor1_hidden_id_shift;
347 });
348
349 // match hidden id
350 static_for<0, ndim_low_1, 1>{}([&](auto idim_low_1) {
351 static_for<0, ndim_bottom_1, 1>{}([&](auto idim_bottom_1) {
352 // if this low dim is bottom dim, then do id matching
353 if constexpr(low_dim_hidden_ids_1[idim_low_1] ==
354 TensorAdaptor1::GetBottomDimensionHiddenIds()[idim_bottom_1])
355 {
356 low_dim_hidden_ids_1_mod_(idim_low_1) =
357 TensorAdaptor0::GetTopDimensionHiddenIds()[idim_bottom_1];
358 }
359 });
360 });
361
362 return low_dim_hidden_ids_1_mod_;
363 }();
364
366 [&](auto i) constexpr { return Number<low_dim_hidden_ids_1_mod[i]>{}; },
368 },
369 Number<TensorAdaptor1::GetNumOfTransform()>{});
370
371 constexpr auto all_low_dim_hidden_idss =
372 container_concat(TensorAdaptor0::GetLowerDimensionHiddenIdss(), low_dim_hidden_idss_1);
373
374 // all_up_dim_hidden_idss =
375 // up_dim_hidden_idss_0 + shift_hidden_id_for_1(up_dim_hiden_idss_1)
376 constexpr auto up_dim_hidden_idss_1 = generate_tuple(
377 // generate sequence of ids for a transform
378 [&](auto itran) {
379 constexpr auto ndim_up_1 = TensorAdaptor1::GetUpperDimensionHiddenIdss()[itran].Size();
380
381 constexpr auto up_dim_hidden_ids_1 =
382 TensorAdaptor1::GetUpperDimensionHiddenIdss()[itran];
383
384 // sequence in, constexpr tuple out
385 constexpr auto up_dim_hidden_ids_1_mod = [&]() constexpr {
386 auto up_dim_hidden_ids_1_mod_ = to_multi_index(up_dim_hidden_ids_1);
387
388 // shift hidden id
389 static_for<0, ndim_up_1, 1>{}([&](auto idim_up_1) {
390 up_dim_hidden_ids_1_mod_(idim_up_1) += adaptor1_hidden_id_shift;
391 });
392
393 return up_dim_hidden_ids_1_mod_;
394 }();
395
396 // constexpr tuple to sequence
398 [&](auto i) constexpr { return Number<up_dim_hidden_ids_1_mod[i]>{}; },
400 },
401 Number<TensorAdaptor1::GetNumOfTransform()>{});
402
403 constexpr auto all_up_dim_hidden_idss =
404 container_concat(TensorAdaptor0::GetUpperDimensionHiddenIdss(), up_dim_hidden_idss_1);
405
406 // bottom_dim_hidden_ids = bottom_dim_hidden_ids_0
407 constexpr auto bottom_dim_hidden_ids = TensorAdaptor0::GetBottomDimensionHiddenIds();
408
409 // top_dim_hidden_ids = shift_hidden_id(top_dim_hidden_ids_1)
410 constexpr auto top_dim_hidden_ids =
411 TensorAdaptor1::GetTopDimensionHiddenIds() + Number<adaptor1_hidden_id_shift>{};
412
413 // put everything together
414 return TensorAdaptor<remove_cv_t<decltype(all_transforms)>,
415 remove_cv_t<decltype(all_low_dim_hidden_idss)>,
416 remove_cv_t<decltype(all_up_dim_hidden_idss)>,
417 remove_cv_t<decltype(bottom_dim_hidden_ids)>,
418 remove_cv_t<decltype(top_dim_hidden_ids)>>{all_transforms};
419}
420
421// Transforms: Tuple<transforms...>
422// LowerDimensionOldTopIdss: Tuple<Sequence<...>, ...>
423// UpperDimensionNewTopIdss: Tuple<Sequence<...>, ...>
424template <typename Transforms, typename LowerDimensionOldTopIdss, typename UpperDimensionNewTopIdss>
425__host__ __device__ constexpr auto make_single_stage_tensor_adaptor(const Transforms& transforms,
426 LowerDimensionOldTopIdss,
427 UpperDimensionNewTopIdss)
428{
429 constexpr index_t ntransform = Transforms::Size();
430
431 static_assert(LowerDimensionOldTopIdss::Size() == ntransform &&
432 UpperDimensionNewTopIdss::Size() == ntransform,
433 "wrong!");
434
435 // sanity check on LowerDimensionOldTopIdss and UpperDimensionNewTopIdss
436 constexpr auto all_low_dim_old_top_ids = unpack(
437 [](auto&&... xs) constexpr { return merge_sequences(xs...); }, LowerDimensionOldTopIdss{});
438
439 constexpr auto all_up_dim_new_top_ids = unpack(
440 [](auto&&... xs) constexpr { return merge_sequences(xs...); }, UpperDimensionNewTopIdss{});
441
442 static_assert(is_valid_sequence_map<decltype(all_low_dim_old_top_ids)>::value &&
443 is_valid_sequence_map<decltype(all_up_dim_new_top_ids)>::value,
444 "wrong!");
445
446 constexpr index_t ndim_old_top = all_low_dim_old_top_ids.Size();
447 constexpr index_t ndim_new_top = all_up_dim_new_top_ids.Size();
448
449 // low_dim_hidden_idss
450 constexpr auto low_dim_hidden_idss = LowerDimensionOldTopIdss{};
451
452 // up_dim_hidden_idss: shift UpperDimensionNewTopIdss by ndim_bottom
453 constexpr auto up_dim_hidden_idss = generate_tuple(
454 [](auto itran) { return UpperDimensionNewTopIdss{}[itran] + Number<ndim_old_top>{}; },
456
457 // bottom_dim_hidden_ids
458 constexpr auto bottom_dim_hidden_ids =
460
461 // top_dim_hidden_ids
462 constexpr auto top_dim_hidden_ids =
464
466 remove_cv_t<decltype(low_dim_hidden_idss)>,
467 remove_cv_t<decltype(up_dim_hidden_idss)>,
468 remove_cv_t<decltype(bottom_dim_hidden_ids)>,
469 remove_cv_t<decltype(top_dim_hidden_ids)>>{transforms};
470}
471
472template <typename X, typename... Xs, typename enable_if<sizeof...(Xs) >= 2, bool>::type = false>
473__host__ __device__ constexpr auto chain_tensor_adaptors(const X& x, const Xs&... xs)
474{
476}
477
478} // namespace ck
__host__ __device__ constexpr T max(T x)
Definition utility/math.hpp:84
__host__ __device__ constexpr T min(T x)
Definition utility/math.hpp:116
Definition ck.hpp:268
__host__ __device__ constexpr auto container_concat(const X &x, const Ys &... ys)
Definition utility/container_helper.hpp:320
int32_t index_t
Definition ck.hpp:299
__host__ __device__ constexpr auto chain_tensor_adaptors(const TensorAdaptor0 &adaptor0, const TensorAdaptor1 &adaptor1)
Definition tensor_description/tensor_adaptor.hpp:245
__host__ __device__ constexpr auto make_single_stage_tensor_adaptor(const Transforms &transforms, LowerDimensionOldTopIdss, UpperDimensionNewTopIdss)
Definition tensor_description/tensor_adaptor.hpp:425
remove_cv_t< remove_reference_t< T > > remove_cvref_t
Definition type.hpp:297
integral_constant< index_t, N > Number
Definition number.hpp:12
__host__ __device__ constexpr auto unpack(F &&f, X &&x)
Definition functional4.hpp:46
__host__ __device__ constexpr auto generate_sequence_v2(F &&f, Number< N >)
Definition sequence_helper.hpp:25
std::enable_if< B, T > enable_if
Definition enable_if.hpp:24
__host__ __device__ constexpr auto to_multi_index(const T &x)
Definition array_multi_index.hpp:28
__host__ __device__ constexpr auto get_container_subset(const Array< T, N > &arr, Sequence< Is... >)
Definition utility/container_helper.hpp:346
__host__ __device__ constexpr auto container_reduce(const Container &x, Reduce reduce, Init init, Number< IBegin >=Number< 0 >{}, Number< IEnd >=Number< Container::Size()>{}, Number< IStep >=Number< 1 >{})
Definition utility/container_helper.hpp:111
__host__ __device__ constexpr auto generate_tuple(F &&f, Number< N >)
Definition tuple_helper.hpp:21
__host__ __device__ constexpr auto make_tuple(Xs &&... xs)
Definition utility/tuple.hpp:211
typename remove_cv< T >::type remove_cv_t
Definition type.hpp:295
__host__ __device__ constexpr void set_container_subset(Array< T, N > &y, Sequence< Is... > picks, const Array< T, sizeof...(Is)> &x)
Definition utility/container_helper.hpp:363
__host__ __device__ constexpr auto merge_sequences(Seqs...)
Definition utility/sequence.hpp:768
Array< index_t, N > MultiIndex
Definition array_multi_index.hpp:12
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1697
__host__ static __device__ constexpr T Max()
Definition numeric_limits.hpp:311
__host__ static __device__ constexpr T Min()
Definition numeric_limits.hpp:310
Definition tensor_description/tensor_adaptor.hpp:23
__host__ static __device__ constexpr index_t GetNumOfTransform()
Definition tensor_description/tensor_adaptor.hpp:24
__host__ static __device__ constexpr index_t GetNumOfBottomDimension()
Definition tensor_description/tensor_adaptor.hpp:99
static constexpr index_t ndim_hidden_
Definition tensor_description/tensor_adaptor.hpp:129
__host__ static __device__ constexpr auto GetLowerDimensionHiddenIdss()
Definition tensor_description/tensor_adaptor.hpp:28
__host__ static __device__ constexpr index_t GetNumOfHiddenDimension()
Definition tensor_description/tensor_adaptor.hpp:109
__host__ __device__ void Print() const
Definition tensor_description/tensor_adaptor.hpp:218
__host__ static __device__ constexpr auto GetUpperDimensionHiddenIdss()
Definition tensor_description/tensor_adaptor.hpp:33
__host__ static __device__ constexpr auto GetBottomDimensionHiddenIds()
Definition tensor_description/tensor_adaptor.hpp:43
__host__ static __device__ constexpr index_t GetNumOfTopDimension()
Definition tensor_description/tensor_adaptor.hpp:104
static constexpr index_t ntransform_
Definition tensor_description/tensor_adaptor.hpp:128
__host__ __device__ constexpr TensorAdaptor()
Definition tensor_description/tensor_adaptor.hpp:144
remove_cv_t< decltype(InitializeElementSize(Transforms{}))> ElementSize
Definition tensor_description/tensor_adaptor.hpp:138
__host__ __device__ constexpr auto GetElementSize() const
Definition tensor_description/tensor_adaptor.hpp:158
__host__ __device__ constexpr TensorAdaptor(const Transforms &transforms)
Definition tensor_description/tensor_adaptor.hpp:147
__host__ static __device__ constexpr auto GetTransformAndItsUpperDimension(Number< IDim >)
Definition tensor_description/tensor_adaptor.hpp:73
MultiIndex< ndim_hidden_ > HiddenIndex
Definition tensor_description/tensor_adaptor.hpp:133
static constexpr index_t ndim_bottom_
Definition tensor_description/tensor_adaptor.hpp:130
__host__ static __device__ constexpr auto InitializeElementSize(const Transforms &transforms)
Definition tensor_description/tensor_adaptor.hpp:48
__host__ static __device__ constexpr bool IsKnownAtCompileTime()
Definition tensor_description/tensor_adaptor.hpp:207
MultiIndex< ndim_bottom_ > BottomIndex
Definition tensor_description/tensor_adaptor.hpp:134
__host__ static __device__ constexpr auto GetTopDimensionHiddenIds()
Definition tensor_description/tensor_adaptor.hpp:38
__host__ __device__ constexpr auto CalculateBottomIndex(const TopIdx &idx_top) const
Definition tensor_description/tensor_adaptor.hpp:175
__host__ __device__ constexpr const auto & GetTransforms() const
Definition tensor_description/tensor_adaptor.hpp:26
MultiIndex< ndim_top_ > TopIndex
Definition tensor_description/tensor_adaptor.hpp:135
static constexpr index_t ndim_top_
Definition tensor_description/tensor_adaptor.hpp:131
typename conditional< kHasContent, type0, type1 >::type type
Definition utility/sequence.hpp:271
Definition is_known_at_compile_time.hpp:14
Definition utility/sequence.hpp:618
Definition utility/math.hpp:211
Definition utility/math.hpp:217
Definition utility/math.hpp:34
Definition utility/sequence.hpp:543
Definition functional2.hpp:33