SimiLie
Loading...
Searching...
No Matches
tensor_prod.hpp
1// SPDX-FileCopyrightText: 2024 Baptiste Legouix
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include <ddc/ddc.hpp>
7
8#include <similie/misc/specialization.hpp>
9
10#include "character.hpp"
11#if defined BUILD_YOUNG_TABLEAU
12#include "young_tableau_tensor.hpp"
13#endif
14
15namespace sil {
16
17namespace tensor {
18
19namespace detail {
20
21template <class Index>
22struct SubindicesDomain;
23
24template <template <class...> class T, class... SubIndex>
25struct SubindicesDomain<T<SubIndex...>>
26{
27 using type = ddc::DiscreteDomain<SubIndex...>;
28
29 static constexpr type run()
30 {
31 return ddc::DiscreteDomain<SubIndex...>(
32 ddc::DiscreteElement<SubIndex...>(ddc::DiscreteElement<SubIndex>(0)...),
33 ddc::DiscreteVector<SubIndex...>(
34 ddc::DiscreteVector<SubIndex>(SubIndex::size())...));
35 }
36};
37
38} // namespace detail
39
40template <class T>
41using subindices_domain_t = detail::SubindicesDomain<T>::type;
42
43template <class T>
44static constexpr subindices_domain_t<T> subindices_domain()
45{
46 return detail::SubindicesDomain<T>::run();
47};
48
49// Check tensor compatibility
50namespace detail {
51
52template <class ProdDDims, class Indices1, class Indices2>
53struct CheckTensorsCompatibility;
54
55template <class... ProdDDim, class... Index1, class... Index2>
56struct CheckTensorsCompatibility<
57 ddc::detail::TypeSeq<ProdDDim...>,
58 ddc::detail::TypeSeq<Index1...>,
59 ddc::detail::TypeSeq<Index2...>>
60{
61 KOKKOS_FUNCTION static constexpr void run()
62 {
63 static_assert(std::is_same_v<
64 ddc::type_seq_remove_t<
65 uncharacterize_t<ddc::to_type_seq_t<
66 ddc::cartesian_prod_t<natural_domain_t<Index1>...>>>,
67 uncharacterize_t<ddc::to_type_seq_t<
68 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>>,
69 ddc::type_seq_remove_t<
70 uncharacterize_t<ddc::to_type_seq_t<
71 ddc::cartesian_prod_t<natural_domain_t<Index2>...>>>,
72 uncharacterize_t<ddc::to_type_seq_t<
73 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>>>);
74 static_assert(are_different_characters_v<
75 ddc::type_seq_remove_t<
76 ddc::to_type_seq_t<
77 ddc::cartesian_prod_t<natural_domain_t<Index1>...>>,
78 ddc::to_type_seq_t<
79 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>,
80 ddc::type_seq_remove_t<
81 ddc::to_type_seq_t<
82 ddc::cartesian_prod_t<natural_domain_t<Index2>...>>,
83 ddc::to_type_seq_t<
84 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>>);
85 }
86};
87
88} // namespace detail
89
90template <class ProdDDims, class Indices1, class Indices2>
92{
93 return detail::CheckTensorsCompatibility<ProdDDims, Indices1, Indices2>::run();
94}
95
96// Any-any product into Any (general case not optimized)
97namespace detail {
98
99template <
100 class ProdDDims,
101 class Indices1,
102 class Indices2,
103 class HeadDDim1TypeSeq,
104 class ContractDDimTypeSeq,
105 class TailDDim2TypeSeq>
106struct TensorProdAnyAnyAny;
107
108template <
109 class... ProdDDim,
110 class... Index1,
111 class... Index2,
112 class... HeadDDim1,
113 class... ContractDDim,
114 class... TailDDim2>
115struct TensorProdAnyAnyAny<
116 ddc::detail::TypeSeq<ProdDDim...>,
117 ddc::detail::TypeSeq<Index1...>,
118 ddc::detail::TypeSeq<Index2...>,
119 ddc::detail::TypeSeq<HeadDDim1...>,
120 ddc::detail::TypeSeq<ContractDDim...>,
121 ddc::detail::TypeSeq<TailDDim2...>>
122{
123 template <class ElementType, class LayoutStridedPolicy, class MemorySpace>
124 KOKKOS_FUNCTION static Tensor<
125 ElementType,
126 ddc::DiscreteDomain<ProdDDim...>,
127 LayoutStridedPolicy,
128 MemorySpace>
129 run(Tensor<ElementType, ddc::DiscreteDomain<ProdDDim...>, LayoutStridedPolicy, MemorySpace>
130 prod_tensor,
131 Tensor<ElementType, ddc::DiscreteDomain<Index1...>, LayoutStridedPolicy, MemorySpace>
132 tensor1,
133 Tensor<ElementType, ddc::DiscreteDomain<Index2...>, LayoutStridedPolicy, MemorySpace>
134 tensor2)
135 {
136 tensor::TensorAccessor<ContractDDim...> contract_accessor;
137 ddc::DiscreteDomain<ContractDDim...> contract_dom = contract_accessor.natural_domain();
138
139 ddc::annotated_for_each(
140 prod_tensor.domain(),
141 [&](ddc::DiscreteElement<ProdDDim...> mem_elem) {
142 auto elem = prod_tensor.canonical_natural_element(mem_elem);
143 prod_tensor.mem(mem_elem) = ddc::annotated_transform_reduce(
144 contract_dom,
145 0.,
146 ddc::reducer::sum<ElementType>(),
147 [&](ddc::DiscreteElement<ContractDDim...> contract_elem) {
148 return tensor1.get(tensor1.access_element(
149 ddc::DiscreteElement<HeadDDim1..., ContractDDim...>(
150 ddc::select<HeadDDim1...>(elem),
151 contract_accessor.access_element(
152 contract_elem))))
153 * tensor2.get(tensor2.access_element(
154 ddc::DiscreteElement<ContractDDim..., TailDDim2...>(
155 contract_elem,
156 ddc::select<TailDDim2...>(elem))));
157 });
158 });
159 return prod_tensor;
160 }
161};
162
163} // namespace detail
164
165template <
166 class... ProdDDim,
167 class... Index1,
168 class... Index2,
169 class ElementType,
170 class LayoutStridedPolicy,
171 class MemorySpace>
172 requires(
173 ((!TensorNatIndex<ProdDDim> || ...) || (!TensorNatIndex<Index2> || ...)
174 || (!TensorNatIndex<Index1> || ...))
175#if defined BUILD_YOUNG_TABLEAU
176 && (!misc::Specialization<ProdDDim, TensorYoungTableauIndex> && ...)
177 && (!misc::Specialization<Index1, TensorYoungTableauIndex> && ...)
178 && (!misc::Specialization<Index2, TensorYoungTableauIndex> && ...)
179#endif
180 )
181Tensor<ElementType, ddc::DiscreteDomain<ProdDDim...>, LayoutStridedPolicy, MemorySpace>
182 KOKKOS_FUNCTION tensor_prod(
183 Tensor<ElementType,
184 ddc::DiscreteDomain<ProdDDim...>,
185 LayoutStridedPolicy,
186 MemorySpace> prod_tensor,
187 Tensor<ElementType,
188 ddc::DiscreteDomain<Index1...>,
189 LayoutStridedPolicy,
190 MemorySpace> tensor1,
191 Tensor<ElementType,
192 ddc::DiscreteDomain<Index2...>,
193 LayoutStridedPolicy,
194 MemorySpace> tensor2)
195{
197 ddc::detail::TypeSeq<ProdDDim...>,
198 ddc::detail::TypeSeq<Index1...>,
199 ddc::detail::TypeSeq<Index2...>>();
200
201 detail::TensorProdAnyAnyAny<
202 uncharacterize_t<ddc::detail::TypeSeq<ProdDDim...>>,
203 uncharacterize_t<ddc::detail::TypeSeq<Index1...>>,
204 uncharacterize_t<ddc::detail::TypeSeq<Index2...>>,
205 ddc::type_seq_remove_t<
206 uncharacterize_t<ddc::to_type_seq_t<
207 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>,
208 uncharacterize_t<ddc::to_type_seq_t<
209 ddc::cartesian_prod_t<natural_domain_t<Index2>...>>>>,
210 ddc::type_seq_remove_t<
212 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<Index1>...>>>,
213 uncharacterize_t<ddc::to_type_seq_t<
214 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>>,
215 ddc::type_seq_remove_t<
216 uncharacterize_t<ddc::to_type_seq_t<
217 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>,
218 uncharacterize_t<ddc::to_type_seq_t<
219 ddc::cartesian_prod_t<natural_domain_t<Index1>...>>>>>::
220 run(uncharacterize_tensor(prod_tensor),
221 uncharacterize_tensor(tensor1),
222 uncharacterize_tensor(tensor2));
223 return prod_tensor;
224}
225
226#if defined BUILD_YOUNG_TABLEAU
227// Young-dense product
228namespace detail {
229
230template <class Index1, class HeadDDim1TypeSeq, class ContractDDimTypeSeq, class TailDDim2TypeSeq>
231struct TensorProdNatYoungNat;
232
233template <class Index1, class... HeadDDim1, class... ContractDDim, class... TailDDim2>
234struct TensorProdNatYoungNat<
235 Index1,
236 ddc::detail::TypeSeq<HeadDDim1...>,
237 ddc::detail::TypeSeq<ContractDDim...>,
238 ddc::detail::TypeSeq<TailDDim2...>>
239{
240 template <class ElementType, class LayoutStridedPolicy, class MemorySpace>
241 static Tensor<
242 ElementType,
243 ddc::DiscreteDomain<HeadDDim1..., TailDDim2...>,
244 LayoutStridedPolicy,
245 MemorySpace>
246 run(Tensor<ElementType,
247 ddc::DiscreteDomain<HeadDDim1..., TailDDim2...>,
248 Kokkos::layout_right,
249 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
250 Tensor<ElementType, ddc::DiscreteDomain<Index1>, LayoutStridedPolicy, MemorySpace> tensor1,
251 Tensor<ElementType,
252 ddc::DiscreteDomain<ContractDDim..., TailDDim2...>,
253 LayoutStridedPolicy,
254 MemorySpace> tensor2)
255 {
256 /*
257 typename TensorYoungTableauIndex<DDim1...>::young_tableau young_tableau;
258 csr::Csr u = young_tableau.template u<YoungTableauIndex, DDim2...>(tensor2.domain());
259*/
260 ddc::Chunk uncompressed_tensor1_alloc(
261 Index1::subindices_domain(),
262 ddc::HostAllocator<double>());
263 tensor::Tensor uncompressed_tensor1(uncompressed_tensor1_alloc);
264
265 tensor::uncompress(uncompressed_tensor1, tensor1);
266
267 return tensor_prod(prod_tensor, uncompressed_tensor1, tensor2);
268 }
269};
270
271} // namespace detail
272
273template <
274 TensorNatIndex... ProdDDim,
275 misc::Specialization<TensorYoungTableauIndex> Index1,
276 TensorNatIndex... DDim2,
277 class ElementType,
278 class LayoutStridedPolicy,
279 class MemorySpace>
280Tensor<ElementType,
281 ddc::DiscreteDomain<ProdDDim...>,
282 Kokkos::layout_right,
283 Kokkos::DefaultHostExecutionSpace::memory_space>
285 Tensor<ElementType,
286 ddc::DiscreteDomain<ProdDDim...>,
287 Kokkos::layout_right,
288 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
289 Tensor<ElementType, ddc::DiscreteDomain<Index1>, LayoutStridedPolicy, MemorySpace> tensor1,
290 Tensor<ElementType, ddc::DiscreteDomain<DDim2...>, LayoutStridedPolicy, MemorySpace>
291 tensor2)
292{
293 /*
294 check_tensors_compatibility<
295 ddc::detail::TypeSeq<ProdDDim...>,
296 ddc::detail::TypeSeq<Index1>,
297 ddc::detail::TypeSeq<DDim2...>>();
298 */
299 // TODO DDim2 -> Index2, characterize
300 return detail::TensorProdNatYoungNat<
301 Index1,
302 ddc::type_seq_remove_t<
303 ddc::detail::TypeSeq<ProdDDim...>,
304 ddc::detail::TypeSeq<DDim2...>>,
305 ddc::type_seq_remove_t<
306 ddc::to_type_seq_t<typename Index1::subindices_domain_t>,
307 ddc::detail::TypeSeq<ProdDDim...>>,
308 ddc::type_seq_remove_t<
309 ddc::detail::TypeSeq<ProdDDim...>,
310 ddc::to_type_seq_t<typename Index1::subindices_domain_t>>>::
311 run(prod_tensor, tensor1, tensor2);
312}
313
314// Young-young product
315namespace detail {
316
317template <
318 class Index1,
319 class Index2,
320 class HeadDDim1TypeSeq,
321 class ContractDDimTypeSeq,
322 class TailDDim2TypeSeq>
323struct TensorProdNatYoungYoung;
324
325template <class Index1, class Index2, class... HeadDDim1, class... ContractDDim, class... TailDDim2>
326struct TensorProdNatYoungYoung<
327 Index1,
328 Index2,
329 ddc::detail::TypeSeq<HeadDDim1...>,
330 ddc::detail::TypeSeq<ContractDDim...>,
331 ddc::detail::TypeSeq<TailDDim2...>>
332{
333 template <class ElementType, class LayoutStridedPolicy, class MemorySpace>
334 static Tensor<
335 ElementType,
336 ddc::DiscreteDomain<HeadDDim1..., TailDDim2...>,
337 LayoutStridedPolicy,
338 MemorySpace>
339 run(Tensor<ElementType,
340 ddc::DiscreteDomain<HeadDDim1..., TailDDim2...>,
341 Kokkos::layout_right,
342 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
343 Tensor<ElementType, ddc::DiscreteDomain<Index1>, LayoutStridedPolicy, MemorySpace> tensor1,
344 Tensor<ElementType, ddc::DiscreteDomain<Index2>, LayoutStridedPolicy, MemorySpace> tensor2)
345 {
346 /*
347 typename TensorYoungTableauIndex<DDim1...>::young_tableau young_tableau;
348 csr::Csr u = young_tableau.template u<YoungTableauIndex, DDim2...>(tensor2.domain());
349*/
350 ddc::Chunk uncompressed_tensor1_alloc(
351 Index1::subindices_domain(),
352 ddc::HostAllocator<double>());
353 tensor::Tensor uncompressed_tensor1(uncompressed_tensor1_alloc);
354
355 ddc::Chunk uncompressed_tensor2_alloc(
356 Index2::subindices_domain(),
357 ddc::HostAllocator<double>());
358 tensor::Tensor uncompressed_tensor2(uncompressed_tensor2_alloc);
359
360 tensor::uncompress(uncompressed_tensor1, tensor1);
361 tensor::uncompress(uncompressed_tensor2, tensor2);
362
363 return tensor_prod(prod_tensor, uncompressed_tensor1, uncompressed_tensor2);
364 }
365};
366
367} // namespace detail
368
369template <
370 TensorNatIndex... ProdDDim,
371 misc::Specialization<TensorYoungTableauIndex> Index1,
372 misc::Specialization<TensorYoungTableauIndex> Index2,
373 class ElementType,
374 class LayoutStridedPolicy,
375 class MemorySpace>
376Tensor<ElementType,
377 ddc::DiscreteDomain<ProdDDim...>,
378 Kokkos::layout_right,
379 Kokkos::DefaultHostExecutionSpace::memory_space>
381 Tensor<ElementType,
382 ddc::DiscreteDomain<ProdDDim...>,
383 Kokkos::layout_right,
384 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
385 Tensor<ElementType, ddc::DiscreteDomain<Index1>, LayoutStridedPolicy, MemorySpace> tensor1,
386 Tensor<ElementType, ddc::DiscreteDomain<Index2>, LayoutStridedPolicy, MemorySpace> tensor2)
387{
389 ddc::detail::TypeSeq<ProdDDim...>,
390 ddc::detail::TypeSeq<Index1>,
391 ddc::detail::TypeSeq<Index2>>();
392
393 detail::TensorProdNatYoungYoung<
394 uncharacterize_t<Index1>,
395 uncharacterize_t<Index2>,
396 ddc::type_seq_remove_t<
397 uncharacterize_t<ddc::to_type_seq_t<
398 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>,
400 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<Index2>>>>>,
401 ddc::type_seq_remove_t<
403 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<Index1>>>>,
404 uncharacterize_t<ddc::to_type_seq_t<
405 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>>,
406 ddc::type_seq_remove_t<
407 uncharacterize_t<ddc::to_type_seq_t<
408 ddc::cartesian_prod_t<natural_domain_t<ProdDDim>...>>>,
410 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<Index1>>>>>>::
411 run(uncharacterize_tensor(prod_tensor),
412 uncharacterize_tensor(tensor1),
413 uncharacterize_tensor(tensor2));
414
415 return prod_tensor;
416}
417
418// Any-any product into Young
419namespace detail {
420
421template <
422 class ProdDDims,
423 class Indices1,
424 class Indices2,
425 class HeadDDim1TypeSeq,
426 class ContractDDimTypeSeq,
427 class TailDDim2TypeSeq>
428struct TensorProdYoungAnyAny;
429
430template <
431 class... ProdDDim,
432 class... Index1,
433 class... Index2,
434 class... HeadDDim1,
435 class... ContractDDim,
436 class... TailDDim2>
437struct TensorProdYoungAnyAny<
438 ddc::detail::TypeSeq<ProdDDim...>,
439 ddc::detail::TypeSeq<Index1...>,
440 ddc::detail::TypeSeq<Index2...>,
441 ddc::detail::TypeSeq<HeadDDim1...>,
442 ddc::detail::TypeSeq<ContractDDim...>,
443 ddc::detail::TypeSeq<TailDDim2...>>
444{
445 template <class ElementType, class LayoutStridedPolicy, class MemorySpace>
446 static Tensor<ElementType, ddc::DiscreteDomain<ProdDDim...>, LayoutStridedPolicy, MemorySpace>
447 run(Tensor<ElementType,
448 ddc::DiscreteDomain<ProdDDim...>,
449 Kokkos::layout_right,
450 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
451 Tensor<ElementType, ddc::DiscreteDomain<Index1...>, LayoutStridedPolicy, MemorySpace>
452 tensor1,
453 Tensor<ElementType, ddc::DiscreteDomain<Index2...>, LayoutStridedPolicy, MemorySpace>
454 tensor2)
455 {
456 /*
457 typename TensorYoungTableauIndex<DDim1...>::young_tableau young_tableau;
458 csr::Csr u = young_tableau.template u<YoungTableauIndex, DDim2...>(tensor2.domain());
459*/
460 ddc::Chunk uncompressed_prod_alloc(
461 ddc::DiscreteDomain(ProdDDim::subindices_domain()...),
462 ddc::HostAllocator<double>());
463 tensor::Tensor uncompressed_prod(uncompressed_prod_alloc);
464
465 tensor::TensorAccessor<ContractDDim...> contract_accessor;
466 ddc::DiscreteDomain<ContractDDim...> contract_dom = contract_accessor.natural_domain();
467
468 ddc::for_each(
469 uncompressed_prod.domain(),
470 [&](ddc::cartesian_prod_t<
471 typename ProdDDim::subindices_domain_t...>::discrete_element_type elem) {
472 uncompressed_prod(elem) = ddc::transform_reduce(
473 contract_dom,
474 0.,
475 ddc::reducer::sum<ElementType>(),
476 [&](ddc::DiscreteElement<ContractDDim...> contract_elem) {
477 return tensor1.get(tensor1.access_element(
478 ddc::DiscreteElement<HeadDDim1..., ContractDDim...>(
479 ddc::select<HeadDDim1...>(elem),
480 contract_accessor.access_element(
481 contract_elem))))
482 * tensor2.get(tensor2.access_element(
483 ddc::DiscreteElement<ContractDDim..., TailDDim2...>(
484 contract_elem,
485 ddc::select<TailDDim2...>(elem))));
486 });
487 });
488 tensor::compress(prod_tensor, uncompressed_prod);
489 return prod_tensor;
490 }
491};
492
493} // namespace detail
494
495template <
496 misc::Specialization<TensorYoungTableauIndex> ProdDDim,
497 class... Index1,
498 class... Index2,
499 class ElementType,
500 class LayoutStridedPolicy,
501 class MemorySpace>
502Tensor<ElementType,
503 ddc::DiscreteDomain<ProdDDim>,
504 Kokkos::layout_right,
505 Kokkos::DefaultHostExecutionSpace::memory_space>
507 Tensor<ElementType,
508 ddc::DiscreteDomain<ProdDDim>,
509 Kokkos::layout_right,
510 Kokkos::DefaultHostExecutionSpace::memory_space> prod_tensor,
511 Tensor<ElementType, ddc::DiscreteDomain<Index1...>, LayoutStridedPolicy, MemorySpace>
512 tensor1,
513 Tensor<ElementType, ddc::DiscreteDomain<Index2...>, LayoutStridedPolicy, MemorySpace>
514 tensor2)
515{
517 ddc::detail::TypeSeq<ProdDDim>,
518 ddc::detail::TypeSeq<Index1...>,
519 ddc::detail::TypeSeq<Index2...>>();
520
521 detail::TensorProdYoungAnyAny<
522 uncharacterize_t<ddc::detail::TypeSeq<ProdDDim>>,
523 uncharacterize_t<ddc::detail::TypeSeq<Index1...>>,
524 uncharacterize_t<ddc::detail::TypeSeq<Index2...>>,
525 ddc::type_seq_remove_t<
527 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<ProdDDim>>>>,
528 uncharacterize_t<ddc::to_type_seq_t<
529 ddc::cartesian_prod_t<natural_domain_t<Index2>...>>>>,
530 ddc::type_seq_remove_t<
532 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<Index1>...>>>,
534 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<ProdDDim>>>>>,
535 ddc::type_seq_remove_t<
537 ddc::to_type_seq_t<ddc::cartesian_prod_t<natural_domain_t<ProdDDim>>>>,
538 uncharacterize_t<ddc::to_type_seq_t<
539 ddc::cartesian_prod_t<natural_domain_t<Index1>...>>>>>::
540 run(uncharacterize_tensor(prod_tensor),
541 uncharacterize_tensor(tensor1),
542 uncharacterize_tensor(tensor2));
543 return prod_tensor;
544}
545#endif
546
547} // namespace tensor
548
549} // namespace sil
static constexpr natural_domain_t natural_domain()
sil::tensor::Tensor< double, ddc::DiscreteDomain< TailTensorIndex... >, Kokkos::layout_right, Kokkos::DefaultHostExecutionSpace::memory_space > tensor_prod(sil::tensor::Tensor< double, ddc::DiscreteDomain< TailTensorIndex... >, Kokkos::layout_right, Kokkos::DefaultHostExecutionSpace::memory_space > prod, sil::tensor::Tensor< double, ddc::DiscreteDomain< HeadTensorIndex >, Kokkos::layout_right, Kokkos::DefaultHostExecutionSpace::memory_space > dense, Csr< N, HeadTensorIndex, TailTensorIndex... > csr)
Definition csr.hpp:107
constexpr void check_tensors_compatibility()
Tensor(ddc::Chunk< ElementType, SupportType, Allocator >) -> Tensor< ElementType, SupportType, Kokkos::layout_right, typename Allocator::memory_space >
constexpr uncharacterize_tensor_t< TensorType > uncharacterize_tensor(TensorType tensor)
constexpr bool are_different_characters_v
detail::SubindicesDomain< T >::type subindices_domain_t
detail::Uncharacterize< Index >::type uncharacterize_t
The top-level namespace of SimiLie.
Definition csr.hpp:14