Line data Source code
1 : #include "DataContainer.h"
2 : #include "DataContainerFormatter.hpp"
3 : #include "FormatConfig.h"
4 : #include "BlockDescriptor.h"
5 : #include "IdenticalBlocksDescriptor.h"
6 : #include "RandomBlocksDescriptor.h"
7 : #include "PartitionDescriptor.h"
8 : #include "Error.h"
9 : #include "TypeCasts.hpp"
10 : #include "Assertions.h"
11 :
12 : #include "Complex.h"
13 :
14 : #include "Functions.hpp"
15 : #include "TypeTraits.hpp"
16 : #include "elsaDefines.h"
17 : #include "functions/Conj.hpp"
18 : #include "functions/Imag.hpp"
19 : #include "functions/Real.hpp"
20 :
21 : #include "reductions/DotProduct.h"
22 : #include "reductions/L0.h"
23 : #include "reductions/L1.h"
24 : #include "reductions/L2.h"
25 : #include "reductions/LInf.h"
26 : #include "reductions/Sum.h"
27 : #include "reductions/Extrema.h"
28 :
29 : #include "transforms/Absolute.h"
30 : #include "transforms/Add.h"
31 : #include "transforms/Assign.h"
32 : #include "transforms/Clip.h"
33 : #include "transforms/Cast.h"
34 : #include "transforms/Sub.h"
35 : #include "transforms/Div.h"
36 : #include "transforms/Extrema.h"
37 : #include "transforms/InplaceAdd.h"
38 : #include "transforms/InplaceSub.h"
39 : #include "transforms/InplaceMul.h"
40 : #include "transforms/InplaceDiv.h"
41 : #include "transforms/Sign.h"
42 : #include "transforms/Square.h"
43 : #include "transforms/Sqrt.h"
44 : #include "transforms/Log.h"
45 : #include "transforms/Lincomb.h"
46 : #include "transforms/Exp.h"
47 : #include "transforms/Imag.h"
48 : #include "transforms/Real.h"
49 : #include "transforms/Bessel.h"
50 : #include "transforms/FFT.h"
51 :
52 : #include <utility>
53 : #include <cmath>
54 : #include <algorithm>
55 :
56 : namespace elsa
57 : {
58 :
59 : template <typename data_t>
60 : void DataContainer<data_t>::assign(const DataContainer<data_t>& other)
61 17271 : {
62 17271 : if (this->getSize() != other.getSize()) {
63 0 : throw InvalidArgumentError("assign: sizes are not equal");
64 0 : }
65 17271 : elsa::assign(other.begin(), other.end(), this->begin());
66 17271 : }
67 :
68 : template <typename data_t>
69 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor)
70 : : _dataDescriptor{dataDescriptor.clone()},
71 : storage_{
72 : ContiguousStorage<data_t>(asUnsigned(_dataDescriptor->getNumberOfCoefficients()))}
73 52954 : {
74 52954 : }
75 :
76 : template <typename data_t>
77 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
78 : const Eigen::Matrix<data_t, Eigen::Dynamic, 1>& data)
79 : : _dataDescriptor{dataDescriptor.clone()},
80 : storage_{std::in_place_type<ContiguousStorage<data_t>>, data.begin(), data.end()}
81 3330 : {
82 3330 : if (getSize() != dataDescriptor.getNumberOfCoefficients())
83 0 : throw InvalidArgumentError("DataContainer: initialization vector has invalid size");
84 3330 : }
85 :
86 : template <typename data_t>
87 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
88 : const ContiguousStorage<data_t>& storage)
89 : : _dataDescriptor{dataDescriptor.clone()}, storage_{storage}
90 628 : {
91 628 : }
92 :
93 : template <typename data_t>
94 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
95 : ContiguousStorageView<data_t> span)
96 : : _dataDescriptor{dataDescriptor.clone()}, storage_{span}
97 109260 : {
98 109260 : }
99 :
100 : template <typename data_t>
101 : template <mr::StorageType tag>
102 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
103 : NdViewTagged<data_t, tag>& view)
104 : : _dataDescriptor{dataDescriptor.clone()}, storage_{ContiguousStorage<data_t>(0)}
105 0 : {
106 0 : static_assert(tag == mr::StorageType::device || tag == mr::StorageType::host
107 0 : || tag == mr::StorageType::universal);
108 :
109 0 : if (tag == mr::StorageType::device && mr::sysStorageType == mr::StorageType::host) {
110 : /* :( */
111 0 : throw std::runtime_error("Unsupported device");
112 0 : }
113 :
114 0 : auto& viewShape = view.shape();
115 0 : size_t dimCount = viewShape.size();
116 0 : if (static_cast<size_t>(dataDescriptor.getNumberOfDimensions()) != dimCount) {
117 0 : throw std::runtime_error("Descriptor and NdView have different dimensionality");
118 0 : }
119 0 : auto descriptorShape = dataDescriptor.getNumberOfCoefficientsPerDimension();
120 0 : for (size_t i = 0; i < dimCount; i++) {
121 0 : if (viewShape(i) != descriptorShape(i)) {
122 0 : throw std::runtime_error(std::string("Mismatch in Descriptor and NdView dimension ")
123 0 : + std::to_string(i));
124 0 : }
125 0 : }
126 :
127 0 : ContiguousStorage<data_t>& storage = std::get<ContiguousStorage<data_t>>(storage_);
128 :
129 0 : if (tag == mr::sysStorageType && view.is_canonical()) {
130 0 : auto sharedCleanupRoutine = view.getCleanup();
131 0 : struct {
132 0 : decltype(sharedCleanupRoutine) cleanup;
133 0 : void operator()()
134 0 : {
135 : /* drop reference to cleanup;
136 : if it reaches 0, cleanup is performed */
137 0 : cleanup.reset();
138 0 : }
139 0 : } cleanupFunctor = {sharedCleanupRoutine};
140 :
141 0 : auto range = view.canonical_range();
142 0 : storage.from_extern(thrust::raw_pointer_cast(range.begin()),
143 0 : range.end() - range.begin(), cleanupFunctor);
144 0 : return;
145 0 : }
146 :
147 0 : auto range = view.range();
148 0 : storage.assign(range.begin(), range.end());
149 0 : }
150 :
151 : template <typename data_t>
152 : DataContainer<data_t>::DataContainer(const DataContainer<data_t>& other)
153 : : _dataDescriptor{other._dataDescriptor->clone()}, storage_{other.storage_}
154 7564 : {
155 7564 : }
156 :
157 : template <typename data_t>
158 : DataContainer<add_complex_t<data_t>> DataContainer<data_t>::asComplex() const
159 572 : {
160 572 : return elsa::asComplex(*this);
161 572 : }
162 :
163 : template <typename data_t>
164 : DataContainer<data_t>& DataContainer<data_t>::operator=(const DataContainer<data_t>& other)
165 8009 : {
166 8009 : if (this != &other) {
167 7767 : _dataDescriptor = other._dataDescriptor->clone();
168 :
169 : // Assign the values from other to this storage, if this is a view, this will not
170 : // reallocate, but write through to the original data container
171 7767 : std::visit(
172 7767 : overloaded{
173 7767 : [](auto& self, const auto other) { self.assign(other.begin(), other.end()); },
174 7767 : },
175 7767 : storage_, other.storage_);
176 7767 : }
177 :
178 8009 : return *this;
179 8009 : }
180 :
181 : template <typename data_t>
182 : DataContainer<data_t>::DataContainer(DataContainer<data_t>&& other) noexcept
183 : : _dataDescriptor{std::move(other._dataDescriptor)}, storage_{std::move(other.storage_)}
184 36452 : {
185 36452 : }
186 :
187 : template <typename data_t>
188 : DataContainer<data_t>& DataContainer<data_t>::operator=(DataContainer<data_t>&& other) noexcept
189 13832 : {
190 13832 : _dataDescriptor = std::move(other._dataDescriptor);
191 :
192 : // If this is a view, we need to write the values from other into this, this is due to the
193 : // dual requirement of data containers to be owning and views
194 13832 : if (isView()) {
195 640 : std::visit(
196 640 : overloaded{
197 640 : [](auto& self, const auto other) { self.assign(other.begin(), other.end()); },
198 640 : },
199 640 : storage_, other.storage_);
200 :
201 13192 : } else {
202 13192 : storage_ = std::move(other.storage_);
203 13192 : }
204 :
205 13832 : return *this;
206 13832 : }
207 :
208 : template <typename data_t>
209 : DataContainer<data_t> DataContainer<data_t>::fromRawData(
210 : data_t* raw_data, mr::StorageType storageType, const IndexVector_t& shape,
211 : const IndexVector_t& strides, const DataDescriptor& desc, std::function<void()> destructor)
212 0 : {
213 0 : switch (storageType) {
214 0 : case mr::StorageType::host: {
215 0 : NdViewTagged<data_t, mr::StorageType::host> view(raw_data, shape, strides,
216 0 : destructor);
217 0 : return DataContainer(desc, view);
218 0 : }
219 0 : case mr::StorageType::device: {
220 0 : NdViewTagged<data_t, mr::StorageType::device> view(raw_data, shape, strides,
221 0 : destructor);
222 0 : return DataContainer(desc, view);
223 0 : }
224 0 : case mr::StorageType::universal: {
225 0 : NdViewTagged<data_t, mr::StorageType::universal> view(raw_data, shape, strides,
226 0 : destructor);
227 0 : return DataContainer(desc, view);
228 0 : }
229 0 : }
230 0 : throw Error("Unknown storage type!");
231 0 : }
232 :
233 : template <typename data_t>
234 : NdView<data_t> DataContainer<data_t>::toNdView() const
235 1 : {
236 1 : auto& desc = getDataDescriptor();
237 1 : const auto& shape_vector = desc.getNumberOfCoefficientsPerDimension();
238 1 : const auto& strides_vector = desc.getProductOfCoefficientsPerDimension();
239 :
240 1 : elsa::mr::NativeContainer<data_t> data = storage().lock_native();
241 1 : return NdView<data_t>(data.raw_pointer, shape_vector, strides_vector, data.release);
242 1 : }
243 :
244 : template <typename data_t>
245 : const DataDescriptor& DataContainer<data_t>::getDataDescriptor() const
246 26227677 : {
247 26227677 : return *_dataDescriptor;
248 26227677 : }
249 :
250 : template <typename data_t>
251 : bool DataContainer<data_t>::isOwning() const
252 710 : {
253 710 : return std::visit(
254 710 : overloaded{[](const auto& storage) {
255 710 : return std::is_same_v<std::decay_t<decltype(storage)>, ContiguousStorage<data_t>>;
256 710 : }},
257 710 : storage_);
258 710 : }
259 :
260 : template <typename data_t>
261 : bool DataContainer<data_t>::isView() const
262 13832 : {
263 13832 : return std::visit(overloaded{[](const auto& storage) {
264 13832 : return std::is_same_v<std::decay_t<decltype(storage)>,
265 13832 : ContiguousStorageView<data_t>>;
266 13832 : }},
267 13832 : storage_);
268 13832 : }
269 :
270 : template <typename data_t>
271 : const ContiguousStorage<data_t>& DataContainer<data_t>::storage() const
272 1614 : {
273 1614 : using RetRef = const ContiguousStorage<data_t>&;
274 1614 : return std::visit(
275 1614 : overloaded{
276 1614 : [](const ContiguousStorage<data_t>& storage) -> RetRef { return storage; },
277 1614 : [](ContiguousStorageView<data_t> storage) -> RetRef { return storage.storage(); }},
278 1614 : storage_);
279 1614 : }
280 :
281 : template <typename data_t>
282 : ContiguousStorage<data_t>& DataContainer<data_t>::storage()
283 261 : {
284 261 : using RetRef = ContiguousStorage<data_t>&;
285 261 : return std::visit(
286 261 : overloaded{
287 261 : [](ContiguousStorage<data_t>& storage) -> RetRef { return storage; },
288 261 : [](ContiguousStorageView<data_t> storage) -> RetRef { return storage.storage(); }},
289 261 : storage_);
290 261 : }
291 :
292 : template <typename data_t>
293 : index_t DataContainer<data_t>::getSize() const
294 49149213 : {
295 49149213 : return std::visit(
296 49149213 : overloaded{
297 49154638 : [](const auto& storage) { return asSigned(storage.size()); },
298 49149213 : },
299 49149213 : storage_);
300 49149213 : }
301 :
302 : template <typename data_t>
303 : index_t DataContainer<data_t>::getNumberOfBlocks() const
304 476 : {
305 476 : if (!is<BlockDescriptor>(getDataDescriptor())) {
306 0 : return 1;
307 0 : }
308 :
309 476 : auto& blockDesc = downcast_safe<BlockDescriptor>(getDataDescriptor());
310 476 : return blockDesc.getNumberOfBlocks();
311 476 : }
312 :
313 : template <typename data_t>
314 : typename DataContainer<data_t>::reference DataContainer<data_t>::operator[](index_t index)
315 28765767 : {
316 28765767 : ELSA_VERIFY(index >= 0);
317 28765767 : ELSA_VERIFY(index < getSize());
318 :
319 28765767 : return std::visit(
320 28765767 : overloaded{
321 28790944 : [index](auto& storage) -> reference { return storage[asUnsigned(index)]; },
322 28765767 : },
323 28765767 : storage_);
324 28765767 : }
325 :
326 : template <typename data_t>
327 : typename DataContainer<data_t>::const_reference
328 : DataContainer<data_t>::operator[](index_t index) const
329 19750436 : {
330 : // ELSA_VERIFY(index >= 0);
331 : // ELSA_VERIFY(index < getSize());
332 :
333 19750436 : return std::visit(
334 19750436 : overloaded{
335 19820302 : [index](const auto& storage) -> const_reference {
336 19820302 : return storage[asUnsigned(index)];
337 19820302 : },
338 19750436 : },
339 19750436 : storage_);
340 19750436 : }
341 :
342 : template <typename data_t>
343 : data_t DataContainer<data_t>::at(const IndexVector_t& coordinate) const
344 0 : {
345 0 : const auto arr = coordinate.array();
346 0 : if ((arr < 0).any()
347 0 : || (arr >= _dataDescriptor->getNumberOfCoefficientsPerDimension().array()).any()) {
348 0 : return 0;
349 0 : }
350 :
351 0 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
352 0 : }
353 :
354 : template <typename data_t>
355 : typename DataContainer<data_t>::reference
356 : DataContainer<data_t>::operator()(const IndexVector_t& coordinate)
357 1018248 : {
358 : // const auto arr = coordinate.array();
359 : // const auto shape = _dataDescriptor->getNumberOfCoefficientsPerDimension().array();
360 : // ELSA_VERIFY((arr >= 0).all());
361 : // ELSA_VERIFY((arr < shape).all());
362 :
363 1018248 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
364 1018248 : }
365 :
366 : template <typename data_t>
367 : typename DataContainer<data_t>::const_reference
368 : DataContainer<data_t>::operator()(const IndexVector_t& coordinate) const
369 123096 : {
370 : // const auto arr = coordinate.array();
371 : // const auto shape = _dataDescriptor->getNumberOfCoefficientsPerDimension().array();
372 : // ELSA_VERIFY((arr >= 0).all());
373 : // ELSA_VERIFY((arr < shape).all());
374 :
375 123096 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
376 123096 : }
377 :
378 : template <typename data_t>
379 : data_t DataContainer<data_t>::dot(const DataContainer<data_t>& other) const
380 2002 : {
381 2002 : return elsa::dot(begin(), end(), other.begin());
382 2002 : }
383 :
384 : template <typename data_t>
385 : GetFloatingPointType_t<data_t> DataContainer<data_t>::squaredL2Norm() const
386 5187 : {
387 5187 : return elsa::squaredL2Norm(begin(), end());
388 5187 : }
389 :
390 : template <typename data_t>
391 : GetFloatingPointType_t<data_t> DataContainer<data_t>::l2Norm() const
392 2267 : {
393 2267 : return elsa::l2Norm(begin(), end());
394 2267 : }
395 :
396 : template <typename data_t>
397 : DataContainer<GetFloatingPointType_t<data_t>> DataContainer<data_t>::pL2Norm() const
398 20 : {
399 20 : if (!is<IdenticalBlocksDescriptor>(getDataDescriptor())) {
400 0 : throw Error("pL2Norm: Descriptor must be of type IdenticalBlocksDescriptor");
401 0 : }
402 :
403 : // Create temporary to hold the running sum of each "column"
404 20 : auto tmp = DataContainer<GetFloatingPointType_t<data_t>>(getBlock(0).getDataDescriptor());
405 20 : tmp = 0;
406 :
407 64 : for (int i = 0; i < getNumberOfBlocks(); ++i) {
408 44 : if constexpr (isComplex<data_t>) {
409 44 : tmp += ::elsa::square(elsa::cwiseAbs(getBlock(i)));
410 44 : } else {
411 44 : tmp += ::elsa::square(getBlock(i));
412 44 : }
413 44 : }
414 :
415 20 : return ::elsa::sqrt(tmp);
416 20 : }
417 :
418 : template <typename data_t>
419 : index_t DataContainer<data_t>::l0PseudoNorm() const
420 7 : {
421 7 : return elsa::l0PseudoNorm(begin(), end());
422 7 : }
423 :
424 : template <typename data_t>
425 : GetFloatingPointType_t<data_t> DataContainer<data_t>::l1Norm() const
426 83 : {
427 83 : return elsa::l1Norm(begin(), end());
428 83 : }
429 :
430 : template <typename data_t>
431 : DataContainer<GetFloatingPointType_t<data_t>> DataContainer<data_t>::pL1Norm() const
432 0 : {
433 0 : if (!is<IdenticalBlocksDescriptor>(getDataDescriptor())) {
434 0 : throw Error("pL1Norm: Descriptor must be of type IdenticalBlocksDescriptor");
435 0 : }
436 :
437 : // Create temporary to hold the running sum of each "column"
438 0 : auto tmp = DataContainer<GetFloatingPointType_t<data_t>>(getBlock(0).getDataDescriptor());
439 0 : tmp = 0;
440 :
441 0 : for (int i = 0; i < getNumberOfBlocks(); ++i) {
442 0 : tmp += ::elsa::cwiseAbs(getBlock(i));
443 0 : }
444 :
445 0 : return tmp;
446 0 : }
447 :
448 : template <typename data_t>
449 : GetFloatingPointType_t<data_t> DataContainer<data_t>::lInfNorm() const
450 9 : {
451 9 : return elsa::lInf(begin(), end());
452 9 : }
453 :
454 : template <typename data_t>
455 : data_t DataContainer<data_t>::l21MixedNorm() const
456 14 : {
457 14 : return l21SmoothMixedNorm(0);
458 14 : }
459 :
460 : template <typename data_t>
461 : data_t DataContainer<data_t>::l21SmoothMixedNorm(data_t epsilon) const
462 16 : {
463 16 : auto tmp = DataContainer(this->getBlock(0).getDataDescriptor());
464 16 : tmp = 0;
465 :
466 56 : for (index_t i = 0; i < this->getNumberOfBlocks(); ++i) {
467 40 : tmp += (square(this->getBlock(i)));
468 40 : }
469 :
470 16 : tmp += (epsilon * epsilon);
471 :
472 16 : return sqrt(tmp).l1Norm();
473 16 : }
474 :
475 : template <typename data_t>
476 : data_t DataContainer<data_t>::sum() const
477 59 : {
478 59 : return elsa::sum(begin(), end());
479 59 : }
480 :
481 : template <typename data_t>
482 : data_t DataContainer<data_t>::minElement() const
483 22 : {
484 22 : return elsa::minElement(begin(), end());
485 22 : }
486 :
487 : template <typename data_t>
488 : data_t DataContainer<data_t>::maxElement() const
489 26 : {
490 26 : return elsa::maxElement(begin(), end());
491 26 : }
492 :
493 : template <typename data_t>
494 : void DataContainer<data_t>::fft(FFTNorm norm, FFTPolicy policy)
495 346 : {
496 346 : std::visit(overloaded{[&](ContiguousStorage<data_t>& storage) {
497 346 : elsa::fft(storage, *_dataDescriptor, norm, policy);
498 346 : },
499 346 : [&](ContiguousStorageView<data_t>& storage) {
500 0 : elsa::fft(storage.storage(), *_dataDescriptor, norm, policy);
501 0 : }},
502 346 : storage_);
503 346 : }
504 :
505 : template <typename data_t>
506 : void DataContainer<data_t>::ifft(FFTNorm norm, FFTPolicy policy)
507 450 : {
508 450 : std::visit(overloaded{[&](ContiguousStorage<data_t>& storage) {
509 450 : elsa::ifft(storage, *_dataDescriptor, norm, policy);
510 450 : },
511 450 : [&](ContiguousStorageView<data_t>& storage) {
512 0 : elsa::ifft(storage.storage(), *_dataDescriptor, norm, policy);
513 0 : }},
514 450 : storage_);
515 450 : }
516 :
517 : template <typename data_t>
518 : DataContainer<data_t>& DataContainer<data_t>::zero() &
519 0 : {
520 0 : return fill(0);
521 0 : }
522 :
523 : template <typename data_t>
524 : DataContainer<data_t> DataContainer<data_t>::zero() &&
525 8 : {
526 8 : return std::move(fill(0));
527 8 : }
528 :
529 : template <typename data_t>
530 : DataContainer<data_t>& DataContainer<data_t>::one() &
531 0 : {
532 0 : return fill(1);
533 0 : }
534 :
535 : template <typename data_t>
536 : DataContainer<data_t> DataContainer<data_t>::one() &&
537 12 : {
538 12 : return std::move(fill(1));
539 12 : }
540 :
541 : template <typename data_t>
542 : DataContainer<data_t>& DataContainer<data_t>::fill(SelfType_t<data_t> value) &
543 24 : {
544 24 : *this = value;
545 24 : return *this;
546 24 : }
547 :
548 : template <typename data_t>
549 : DataContainer<data_t> DataContainer<data_t>::fill(SelfType_t<data_t> value) &&
550 34217 : {
551 34217 : *this = value;
552 34217 : return std::move(*this);
553 34217 : }
554 :
555 : template <typename data_t>
556 : DataContainer<data_t>& DataContainer<data_t>::operator+=(const DataContainer<data_t>& dc)
557 3126 : {
558 3126 : elsa::inplaceAdd(begin(), end(), dc.begin());
559 3126 : return *this;
560 3126 : }
561 :
562 : template <typename data_t>
563 : DataContainer<data_t>& DataContainer<data_t>::operator-=(const DataContainer<data_t>& dc)
564 6333 : {
565 6333 : elsa::inplaceSub(begin(), end(), dc.begin());
566 6333 : return *this;
567 6333 : }
568 :
569 : template <typename data_t>
570 : DataContainer<data_t>& DataContainer<data_t>::operator*=(const DataContainer<data_t>& dc)
571 10238 : {
572 10238 : elsa::inplaceMul(begin(), end(), dc.begin());
573 10238 : return *this;
574 10238 : }
575 :
576 : template <typename data_t>
577 : DataContainer<data_t>& DataContainer<data_t>::operator/=(const DataContainer<data_t>& dc)
578 17 : {
579 17 : elsa::inplaceDiv(begin(), end(), dc.begin());
580 17 : return *this;
581 17 : }
582 :
583 : template <typename data_t>
584 : DataContainer<data_t>& DataContainer<data_t>::operator+=(data_t scalar)
585 41 : {
586 41 : elsa::inplaceAddScalar(begin(), end(), scalar);
587 41 : return *this;
588 41 : }
589 :
590 : template <typename data_t>
591 : DataContainer<data_t>& DataContainer<data_t>::operator-=(data_t scalar)
592 9 : {
593 9 : elsa::inplaceSubScalar(begin(), end(), scalar);
594 9 : return *this;
595 9 : }
596 :
597 : template <typename data_t>
598 : DataContainer<data_t>& DataContainer<data_t>::operator*=(data_t scalar)
599 5790 : {
600 5790 : elsa::inplaceMulScalar(begin(), end(), scalar);
601 5790 : return *this;
602 5790 : }
603 :
604 : template <typename data_t>
605 : DataContainer<data_t>& DataContainer<data_t>::operator/=(data_t scalar)
606 332 : {
607 332 : elsa::inplaceDivScalar(begin(), end(), scalar);
608 332 : return *this;
609 332 : }
610 :
611 : template <typename data_t>
612 : DataContainer<data_t>& DataContainer<data_t>::operator=(data_t scalar)
613 56357 : {
614 56357 : elsa::fill(begin(), end(), scalar);
615 56357 : return *this;
616 56357 : }
617 :
618 : template <typename data_t>
619 : bool DataContainer<data_t>::operator==(const DataContainer<data_t>& other) const
620 1496 : {
621 1496 : if (*_dataDescriptor != *other._dataDescriptor)
622 0 : return false;
623 :
624 : // if (*_dataHandler != *other._dataHandler)
625 : // return false;
626 :
627 1496 : return true;
628 1496 : }
629 :
630 : template <typename data_t>
631 : bool DataContainer<data_t>::operator!=(const DataContainer<data_t>& other) const
632 94 : {
633 94 : return !(*this == other);
634 94 : }
635 :
636 : template <typename data_t>
637 : DataContainer<data_t> DataContainer<data_t>::getBlock(index_t i)
638 71547 : {
639 71547 : const auto blockDesc = downcast_safe<BlockDescriptor>(_dataDescriptor.get());
640 71547 : if (!blockDesc)
641 5 : throw LogicError("DataContainer: cannot get block from not-blocked container");
642 :
643 71542 : if (i >= blockDesc->getNumberOfBlocks() || i < 0)
644 0 : throw InvalidArgumentError("DataContainer: block index out of bounds");
645 :
646 71542 : size_t startIndex = asUnsigned(blockDesc->getOffsetOfBlock(i));
647 71542 : const auto& ithDesc = blockDesc->getDescriptorOfBlock(i);
648 71542 : size_t blockSize = asUnsigned(ithDesc.getNumberOfCoefficients());
649 :
650 71542 : return std::visit(overloaded{[&](ContiguousStorage<data_t>& storage) {
651 35622 : auto span = ContiguousStorageView<data_t>(
652 35622 : storage, startIndex, startIndex + blockSize);
653 35622 : return DataContainer<data_t>{ithDesc, span};
654 35622 : },
655 71542 : [&](ContiguousStorageView<data_t> storage) {
656 35591 : auto span = ContiguousStorageView<data_t>(
657 35591 : storage.storage(), storage.offset() + startIndex,
658 35591 : storage.offset() + startIndex + blockSize);
659 35591 : return DataContainer<data_t>{ithDesc, span};
660 35591 : }},
661 71542 : storage_);
662 71542 : }
663 :
664 : template <typename data_t>
665 : const DataContainer<data_t> DataContainer<data_t>::getBlock(index_t i) const
666 1226 : {
667 1226 : const auto blockDesc = downcast_safe<BlockDescriptor>(_dataDescriptor.get());
668 1226 : if (!blockDesc)
669 5 : throw LogicError("DataContainer: cannot get block from not-blocked container");
670 :
671 1221 : if (i >= blockDesc->getNumberOfBlocks() || i < 0)
672 0 : throw InvalidArgumentError("DataContainer: block index out of bounds");
673 :
674 1221 : size_t startIndex = asUnsigned(blockDesc->getOffsetOfBlock(i));
675 1221 : const auto& ithDesc = blockDesc->getDescriptorOfBlock(i);
676 1221 : size_t blockSize = asUnsigned(ithDesc.getNumberOfCoefficients());
677 :
678 1221 : return std::visit(overloaded{[&](const ContiguousStorage<data_t>& storage) {
679 385 : auto span = ContiguousStorageView<data_t>(
680 : // Casting const away is okay, as we return a const
681 : // container
682 385 : const_cast<ContiguousStorage<data_t>&>(storage),
683 385 : startIndex, startIndex + blockSize);
684 385 : return DataContainer<data_t>{ithDesc, span};
685 385 : },
686 1221 : [&](ContiguousStorageView<data_t> storage) {
687 836 : auto span = ContiguousStorageView<data_t>(
688 836 : storage.storage(), storage.offset() + startIndex,
689 836 : storage.offset() + startIndex + blockSize);
690 836 : return DataContainer<data_t>{ithDesc, span};
691 836 : }},
692 1221 : storage_);
693 1221 : }
694 :
695 : template <typename data_t>
696 : DataContainer<data_t> DataContainer<data_t>::viewAs(const DataDescriptor& dataDescriptor)
697 35835 : {
698 35835 : if (dataDescriptor.getNumberOfCoefficients() != getSize())
699 0 : throw InvalidArgumentError("DataContainer: view must have same size as container");
700 :
701 35835 : return std::visit(overloaded{[&](ContiguousStorage<data_t>& storage) {
702 1224 : auto span = ContiguousStorageView<data_t>(
703 1224 : storage, 0,
704 1224 : asUnsigned(dataDescriptor.getNumberOfCoefficients()));
705 1224 : return DataContainer<data_t>{dataDescriptor, span};
706 1224 : },
707 35835 : [&](ContiguousStorageView<data_t> storage) {
708 34502 : return DataContainer<data_t>{dataDescriptor, storage};
709 34502 : }},
710 35835 : storage_);
711 35835 : }
712 :
713 : template <typename data_t>
714 : const DataContainer<data_t>
715 : DataContainer<data_t>::viewAs(const DataDescriptor& dataDescriptor) const
716 938 : {
717 938 : if (dataDescriptor.getNumberOfCoefficients() != getSize())
718 0 : throw InvalidArgumentError("DataContainer: view must have same size as container");
719 :
720 938 : return std::visit(overloaded{[&](const ContiguousStorage<data_t>& storage) {
721 816 : auto span = ContiguousStorageView<data_t>(
722 816 : const_cast<ContiguousStorage<data_t>&>(storage), 0,
723 816 : asUnsigned(dataDescriptor.getNumberOfCoefficients()));
724 816 : return DataContainer<data_t>{dataDescriptor, span};
725 816 : },
726 938 : [&](ContiguousStorageView<data_t> storage) {
727 122 : return DataContainer<data_t>{dataDescriptor, storage};
728 122 : }},
729 938 : storage_);
730 938 : }
731 :
732 : template <typename data_t>
733 : const DataContainer<data_t> DataContainer<data_t>::slice(index_t i) const
734 666 : {
735 666 : auto& desc = getDataDescriptor();
736 666 : auto dim = desc.getNumberOfDimensions();
737 666 : auto sizeOfLastDim = desc.getNumberOfCoefficientsPerDimension()[dim - 1];
738 :
739 666 : if (i >= sizeOfLastDim) {
740 8 : throw LogicError("Trying to access out of bound slice");
741 8 : }
742 :
743 658 : if (sizeOfLastDim == 1) {
744 4 : return *this;
745 4 : }
746 :
747 654 : auto sliceDesc = PartitionDescriptor(desc, sizeOfLastDim);
748 :
749 : // Now set the slice
750 654 : return viewAs(sliceDesc).getBlock(i);
751 654 : }
752 :
753 : template <typename data_t>
754 : DataContainer<data_t> DataContainer<data_t>::slice(index_t i)
755 35405 : {
756 35405 : auto& desc = getDataDescriptor();
757 35405 : auto dim = desc.getNumberOfDimensions();
758 35405 : auto sizeOfLastDim = desc.getNumberOfCoefficientsPerDimension()[dim - 1];
759 :
760 35405 : if (i >= sizeOfLastDim) {
761 4 : throw LogicError("Trying to access out of bound slice");
762 4 : }
763 :
764 35401 : if (sizeOfLastDim == 1) {
765 4 : return *this;
766 4 : }
767 :
768 35397 : auto sliceDesc = PartitionDescriptor(desc, sizeOfLastDim);
769 :
770 : // Now set the slice
771 35397 : return viewAs(sliceDesc).getBlock(i);
772 35397 : }
773 :
774 : template <typename data_t>
775 : typename DataContainer<data_t>::iterator DataContainer<data_t>::begin()
776 108522 : {
777 108522 : return std::visit(
778 108522 : overloaded{
779 108522 : [](auto& storage) { return storage.begin(); },
780 108522 : },
781 108522 : storage_);
782 108522 : }
783 :
784 : template <typename data_t>
785 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::begin() const
786 65617 : {
787 65617 : return cbegin();
788 65617 : }
789 :
790 : template <typename data_t>
791 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::cbegin() const
792 65623 : {
793 65623 : return std::visit(
794 65623 : overloaded{
795 65623 : [](const auto& storage) { return storage.cbegin(); },
796 65623 : },
797 65623 : storage_);
798 65623 : }
799 :
800 : template <typename data_t>
801 : typename DataContainer<data_t>::iterator DataContainer<data_t>::end()
802 82156 : {
803 82156 : return std::visit(
804 82156 : overloaded{
805 82172 : [](auto& storage) { return storage.end(); },
806 82156 : },
807 82156 : storage_);
808 82156 : }
809 :
810 : template <typename data_t>
811 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::end() const
812 36866 : {
813 36866 : return cend();
814 36866 : }
815 :
816 : template <typename data_t>
817 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::cend() const
818 36872 : {
819 36872 : return std::visit(
820 36872 : overloaded{
821 36872 : [](const auto& storage) { return storage.cend(); },
822 36872 : },
823 36872 : storage_);
824 36872 : }
825 :
826 : template <typename data_t>
827 : void DataContainer<data_t>::format(std::ostream& os, format_config cfg) const
828 0 : {
829 0 : DataContainerFormatter<data_t> fmt{cfg};
830 0 : fmt.format(os, *this);
831 0 : }
832 :
833 : template <typename data_t>
834 : DataContainer<data_t> concatenate(const DataContainer<data_t>& dc1,
835 : const DataContainer<data_t>& dc2)
836 28 : {
837 28 : auto desc1 = dc1.getDataDescriptor().clone();
838 28 : auto desc2 = dc2.getDataDescriptor().clone();
839 :
840 28 : if (desc1->getNumberOfDimensions() != desc2->getNumberOfDimensions()) {
841 4 : throw LogicError("Can't concatenate two DataContainers with different dimension");
842 4 : }
843 :
844 24 : std::vector<std::unique_ptr<DataDescriptor>> descriptors;
845 24 : descriptors.reserve(2);
846 24 : descriptors.push_back(std::move(desc1));
847 24 : descriptors.push_back(std::move(desc2));
848 :
849 24 : auto blockDesc = RandomBlocksDescriptor(descriptors);
850 24 : auto concatenated = DataContainer<data_t>(blockDesc);
851 :
852 24 : concatenated.getBlock(0) = dc1;
853 24 : concatenated.getBlock(1) = dc2;
854 24 : return concatenated;
855 24 : }
856 :
857 : template <typename data_t>
858 : [[nodiscard]] DataContainer<data_t> fftShift(const DataContainer<data_t>& dc)
859 0 : {
860 0 : const DataDescriptor& desc = dc.getDataDescriptor();
861 0 : IndexVector_t numOfCoeffsPerDim = desc.getNumberOfCoefficientsPerDimension();
862 :
863 0 : IndexVector_t midPoint = numOfCoeffsPerDim / 2;
864 :
865 0 : DataContainer<data_t> copy{desc};
866 0 : for (index_t i = 0; i < desc.getNumberOfCoefficients(); ++i) {
867 0 : IndexVector_t idx = desc.getCoordinateFromIndex(i);
868 0 : IndexVector_t shifted{idx};
869 0 : for (index_t j = 0; j < desc.getNumberOfDimensions(); ++j) {
870 0 : shifted[j] = (idx[j] + midPoint[j]) % numOfCoeffsPerDim[j];
871 0 : }
872 0 : copy(shifted) = dc(idx);
873 0 : }
874 0 : return copy;
875 0 : }
876 :
877 : template <typename data_t>
878 : DataContainer<data_t> ifftShift(const DataContainer<data_t>& dc)
879 5 : {
880 5 : const DataDescriptor& desc = dc.getDataDescriptor();
881 5 : IndexVector_t numOfCoeffsPerDim = desc.getNumberOfCoefficientsPerDimension();
882 :
883 5 : IndexVector_t midPoint = -numOfCoeffsPerDim / 2;
884 :
885 5 : DataContainer<data_t> copy{desc};
886 95 : for (index_t i = 0; i < desc.getNumberOfCoefficients(); ++i) {
887 90 : IndexVector_t idx = desc.getCoordinateFromIndex(i);
888 90 : IndexVector_t shifted{idx};
889 270 : for (index_t j = 0; j < desc.getNumberOfDimensions(); ++j) {
890 180 : shifted[j] = ((idx[j] + midPoint[j]) + numOfCoeffsPerDim[j]) % numOfCoeffsPerDim[j];
891 180 : }
892 90 : copy(shifted) = dc(idx);
893 90 : }
894 5 : return copy;
895 5 : }
896 :
897 : template <typename data_t>
898 : DataContainer<data_t> fftShift2D(const DataContainer<data_t>& dc)
899 24 : {
900 24 : assert(dc.getDataDescriptor().getNumberOfDimensions() == 2
901 24 : && "DataContainer::fftShift2D: currently only supporting 2D signals");
902 :
903 24 : const DataDescriptor& dataDescriptor = dc.getDataDescriptor();
904 24 : IndexVector_t numOfCoeffsPerDim = dataDescriptor.getNumberOfCoefficientsPerDimension();
905 24 : index_t m = numOfCoeffsPerDim[0];
906 24 : index_t n = numOfCoeffsPerDim[1];
907 :
908 24 : index_t firstShift = m / 2;
909 24 : index_t secondShift = n / 2;
910 :
911 24 : DataContainer<data_t> copyDC(dataDescriptor);
912 :
913 96 : for (index_t i = 0; i < m; ++i) {
914 352 : for (index_t j = 0; j < n; ++j) {
915 280 : copyDC((i + firstShift) % m, (j + secondShift) % n) = dc(i, j);
916 280 : }
917 72 : }
918 :
919 24 : return copyDC;
920 24 : }
921 :
922 : template <typename data_t>
923 : DataContainer<data_t> ifftShift2D(const DataContainer<data_t>& dc)
924 24 : {
925 24 : assert(dc.getDataDescriptor().getNumberOfDimensions() == 2
926 24 : && "DataContainer::ifftShift2D: currently only supporting 2D signals");
927 :
928 24 : const DataDescriptor& dataDescriptor = dc.getDataDescriptor();
929 24 : IndexVector_t numOfCoeffsPerDim = dataDescriptor.getNumberOfCoefficientsPerDimension();
930 24 : index_t m = numOfCoeffsPerDim[0];
931 24 : index_t n = numOfCoeffsPerDim[1];
932 :
933 24 : index_t firstShift = -m / 2;
934 24 : index_t secondShift = -n / 2;
935 :
936 24 : DataContainer<data_t> copyDC(dataDescriptor);
937 :
938 96 : for (index_t i = 0; i < m; ++i) {
939 352 : for (index_t j = 0; j < n; ++j) {
940 280 : index_t leftIndex = (((i + firstShift) % m) + m) % m;
941 280 : index_t rightIndex = (((j + secondShift) % n) + n) % n;
942 280 : copyDC(leftIndex, rightIndex) = dc(i, j);
943 280 : }
944 72 : }
945 :
946 24 : return copyDC;
947 24 : }
948 :
949 : template <typename data_t>
950 : DataContainer<data_t> clip(const DataContainer<data_t>& dc, data_t min, data_t max)
951 178 : {
952 178 : DataContainer<data_t> copy(dc.getDataDescriptor());
953 178 : elsa::clip(dc.begin(), dc.end(), copy.begin(), min, max);
954 178 : return copy;
955 178 : }
956 :
957 : template <typename data_t>
958 : DataContainer<data_t> exp(const DataContainer<data_t>& dc)
959 102 : {
960 102 : DataContainer<data_t> copy(dc.getDataDescriptor());
961 102 : elsa::exp(dc.begin(), dc.end(), copy.begin());
962 102 : return copy;
963 102 : }
964 :
965 : template <typename data_t>
966 : DataContainer<data_t> log(const DataContainer<data_t>& dc)
967 33 : {
968 33 : DataContainer<data_t> copy(dc.getDataDescriptor());
969 33 : elsa::log(dc.begin(), dc.end(), copy.begin());
970 33 : return copy;
971 33 : }
972 :
973 : template <typename data_t>
974 : DataContainer<data_t> square(const DataContainer<data_t>& dc)
975 151 : {
976 151 : DataContainer<data_t> copy(dc.getDataDescriptor());
977 151 : elsa::square(dc.begin(), dc.end(), copy.begin());
978 151 : return copy;
979 151 : }
980 :
981 : template <typename data_t>
982 : DataContainer<data_t> sq(const DataContainer<data_t>& dc)
983 54 : {
984 54 : return square(dc);
985 54 : }
986 :
987 : template <typename data_t>
988 : DataContainer<data_t> sqrt(const DataContainer<data_t>& dc)
989 43 : {
990 43 : DataContainer<data_t> copy(dc.getDataDescriptor());
991 43 : elsa::sqrt(dc.begin(), dc.end(), copy.begin());
992 43 : return copy;
993 43 : }
994 :
995 : template <typename data_t>
996 : DataContainer<data_t> minimum(const DataContainer<data_t>& dc, SelfType_t<data_t> scalar)
997 7 : {
998 7 : DataContainer<data_t> copy(dc.getDataDescriptor());
999 7 : elsa::minimum(dc.begin(), dc.end(), scalar, copy.begin());
1000 7 : return copy;
1001 7 : }
1002 :
1003 : template <typename data_t>
1004 : DataContainer<data_t> maximum(const DataContainer<data_t>& dc, SelfType_t<data_t> scalar)
1005 178 : {
1006 178 : DataContainer<data_t> copy(dc.getDataDescriptor());
1007 178 : elsa::maximum(dc.begin(), dc.end(), scalar, copy.begin());
1008 178 : return copy;
1009 178 : }
1010 :
1011 : template <class data_t>
1012 : DataContainer<data_t> materialize(const DataContainer<data_t>& x)
1013 710 : {
1014 710 : if (x.isOwning()) {
1015 82 : return x;
1016 628 : } else {
1017 628 : ContiguousStorage<data_t> storage(x.begin(), x.end());
1018 628 : return DataContainer(x.getDataDescriptor(), storage);
1019 628 : }
1020 710 : }
1021 :
1022 : template <class data_t>
1023 : DataContainer<data_t> bessel_log_0(const DataContainer<data_t>& dc)
1024 4 : {
1025 4 : DataContainer<data_t> copy(dc.getDataDescriptor());
1026 4 : elsa::bessel_log_0(dc.begin(), dc.end(), copy.begin());
1027 4 : return copy;
1028 4 : }
1029 :
1030 : template <class data_t>
1031 : DataContainer<data_t> bessel_1_0(const DataContainer<data_t>& dc)
1032 8 : {
1033 8 : DataContainer<data_t> copy(dc.getDataDescriptor());
1034 8 : elsa::bessel_1_0(dc.begin(), dc.end(), copy.begin());
1035 8 : return copy;
1036 8 : }
1037 :
1038 : template <typename data_t>
1039 : DataContainer<value_type_of_t<data_t>> cwiseAbs(const DataContainer<data_t>& dc)
1040 117 : {
1041 117 : using T = GetFloatingPointType_t<data_t>;
1042 117 : DataContainer<T> copy(dc.getDataDescriptor());
1043 :
1044 117 : elsa::cwiseAbs(dc.begin(), dc.end(), copy.begin());
1045 117 : return copy;
1046 117 : }
1047 :
1048 : template <typename data_t>
1049 : DataContainer<value_type_of_t<data_t>> sign(const DataContainer<data_t>& dc)
1050 109 : {
1051 109 : using T = GetFloatingPointType_t<data_t>;
1052 109 : DataContainer<T> copy(dc.getDataDescriptor());
1053 :
1054 109 : elsa::sign(dc.begin(), dc.end(), copy.begin());
1055 109 : return copy;
1056 109 : }
1057 :
1058 : template <typename data_t>
1059 : DataContainer<value_type_of_t<data_t>> real(const DataContainer<data_t>& dc)
1060 207 : {
1061 207 : DataContainer<value_type_of_t<data_t>> result(dc.getDataDescriptor());
1062 207 : elsa::real(dc.begin(), dc.end(), result.begin());
1063 207 : return result;
1064 207 : }
1065 :
1066 : template <typename data_t>
1067 : DataContainer<value_type_of_t<data_t>> imag(const DataContainer<data_t>& dc)
1068 5 : {
1069 5 : DataContainer<value_type_of_t<data_t>> result(dc.getDataDescriptor());
1070 5 : elsa::imag(dc.begin(), dc.end(), result.begin());
1071 5 : return result;
1072 5 : }
1073 :
1074 : template <typename data_t>
1075 : DataContainer<add_complex_t<data_t>> asComplex(const DataContainer<data_t>& dc)
1076 572 : {
1077 572 : if constexpr (isComplex<data_t>) {
1078 448 : return dc;
1079 448 : } else {
1080 448 : DataContainer<complex<data_t>> ret{dc.getDataDescriptor()};
1081 :
1082 : // extend with complex zero value
1083 448 : elsa::cast(dc.begin(), dc.end(), ret.begin());
1084 448 : return ret;
1085 448 : }
1086 572 : }
1087 :
1088 : template <typename data_t>
1089 : DataContainer<data_t> operator-(const DataContainer<data_t>& lhs,
1090 : const DataContainer<data_t>& rhs)
1091 1982 : {
1092 : // TODO: Do size checking!
1093 1982 : DataContainer<data_t> ret{lhs.getDataDescriptor()};
1094 1982 : elsa::sub(lhs.begin(), lhs.end(), rhs.begin(), ret.begin());
1095 1982 : return ret;
1096 1982 : }
1097 :
1098 : template <typename data_t, typename Scalar, typename>
1099 : DataContainer<std::common_type_t<data_t, Scalar>> operator-(const DataContainer<data_t>& dc,
1100 : const Scalar& s)
1101 111 : {
1102 111 : using T = std::common_type_t<data_t, Scalar>;
1103 :
1104 111 : DataContainer<T> ret{dc.getDataDescriptor()};
1105 111 : elsa::subScalar(dc.begin(), dc.end(), T(s), ret.begin());
1106 111 : return ret;
1107 111 : }
1108 :
1109 : template <typename Scalar, typename data_t, typename>
1110 : DataContainer<std::common_type_t<Scalar, data_t>> operator-(const Scalar& s,
1111 : const DataContainer<data_t>& dc)
1112 29 : {
1113 29 : using T = std::common_type_t<Scalar, data_t>;
1114 :
1115 29 : DataContainer<T> ret{dc.getDataDescriptor()};
1116 29 : elsa::subScalar(T(s), dc.begin(), dc.end(), ret.begin());
1117 29 : return ret;
1118 29 : }
1119 :
1120 : template <typename data_t>
1121 : DataContainer<data_t> operator/(const DataContainer<data_t>& lhs,
1122 : const DataContainer<data_t>& rhs)
1123 67 : {
1124 67 : DataContainer<data_t> ret{lhs.getDataDescriptor()};
1125 67 : elsa::div(lhs.begin(), lhs.end(), rhs.begin(), ret.begin());
1126 67 : return ret;
1127 67 : }
1128 :
1129 : template <typename data_t, typename Scalar, typename>
1130 : DataContainer<std::common_type_t<data_t, Scalar>> operator/(const DataContainer<data_t>& dc,
1131 : const Scalar& s)
1132 45 : {
1133 45 : using T = std::common_type_t<data_t, Scalar>;
1134 :
1135 45 : DataContainer<T> ret{dc.getDataDescriptor()};
1136 45 : elsa::divScalar(dc.begin(), dc.end(), T(s), ret.begin());
1137 45 : return ret;
1138 45 : }
1139 :
1140 : template <typename Scalar, typename data_t, typename>
1141 : DataContainer<std::common_type_t<Scalar, data_t>> operator/(const Scalar& s,
1142 : const DataContainer<data_t>& dc)
1143 39 : {
1144 39 : using T = std::common_type_t<Scalar, data_t>;
1145 :
1146 39 : DataContainer<T> ret{dc.getDataDescriptor()};
1147 39 : elsa::divScalar(T(s), dc.begin(), dc.end(), ret.begin());
1148 39 : return ret;
1149 39 : }
1150 :
1151 : template <typename xdata_t, typename ydata_t>
1152 : DataContainer<value_type_of_t<std::common_type_t<xdata_t, ydata_t>>>
1153 : cwiseMax(const DataContainer<xdata_t>& lhs, const DataContainer<ydata_t>& rhs)
1154 20 : {
1155 20 : using data_t = value_type_of_t<std::common_type_t<xdata_t, ydata_t>>;
1156 :
1157 20 : DataContainer<data_t> copy(rhs.getDataDescriptor());
1158 20 : elsa::cwiseMax(lhs.begin(), lhs.end(), rhs.begin(), copy.begin());
1159 20 : return copy;
1160 20 : }
1161 :
1162 : template <typename xdata_t, typename ydata_t>
1163 : DataContainer<value_type_of_t<std::common_type_t<xdata_t, ydata_t>>>
1164 : cwiseMin(const DataContainer<xdata_t>& lhs, const DataContainer<ydata_t>& rhs)
1165 0 : {
1166 0 : using data_t = value_type_of_t<std::common_type_t<xdata_t, ydata_t>>;
1167 :
1168 0 : DataContainer<data_t> copy(rhs.getDataDescriptor());
1169 0 : elsa::cwiseMin(lhs.begin(), lhs.end(), rhs.begin(), copy.begin());
1170 0 : return copy;
1171 0 : }
1172 :
1173 : template <class data_t>
1174 : DataContainer<data_t> lincomb(SelfType_t<data_t> a, const DataContainer<data_t>& x,
1175 : SelfType_t<data_t> b, const DataContainer<data_t>& y)
1176 20 : {
1177 20 : if (x.getDataDescriptor() != y.getDataDescriptor()) {
1178 8 : throw InvalidArgumentError("lincomb: x and y are of different size");
1179 8 : }
1180 :
1181 12 : auto out = DataContainer<data_t>(x.getDataDescriptor());
1182 12 : lincomb(a, x, b, y, out);
1183 12 : return out;
1184 12 : }
1185 :
1186 : template <class data_t>
1187 : void lincomb(SelfType_t<data_t> a, const DataContainer<data_t>& x, SelfType_t<data_t> b,
1188 : const DataContainer<data_t>& y, DataContainer<data_t>& out)
1189 5182 : {
1190 5182 : if (x.getDataDescriptor() != y.getDataDescriptor()) {
1191 0 : throw InvalidArgumentError("lincomb: x and y are of different size");
1192 0 : }
1193 :
1194 5182 : if (x.getDataDescriptor() != out.getDataDescriptor()) {
1195 4 : throw InvalidArgumentError("lincomb: input and output vectors are of different size");
1196 4 : }
1197 :
1198 5178 : lincomb(a, x.begin(), x.end(), b, y.begin(), out.begin());
1199 5178 : }
1200 :
1201 : template <class data_t>
1202 : DataContainer<data_t> zeros(const DataDescriptor& desc)
1203 74 : {
1204 74 : return full<data_t>(desc, 0);
1205 74 : }
1206 :
1207 : template <class data_t>
1208 : DataContainer<data_t> zeroslike(const DataContainer<data_t>& dc)
1209 30 : {
1210 30 : return zeros<data_t>(dc.getDataDescriptor());
1211 30 : }
1212 :
1213 : template <class data_t>
1214 : DataContainer<data_t> ones(const DataDescriptor& desc)
1215 16 : {
1216 16 : return full<data_t>(desc, 1);
1217 16 : }
1218 :
1219 : template <class data_t>
1220 : DataContainer<data_t> oneslike(const DataContainer<data_t>& dc)
1221 4 : {
1222 4 : return ones<data_t>(dc.getDataDescriptor());
1223 4 : }
1224 :
1225 : template <class data_t>
1226 : DataContainer<data_t> full(const DataDescriptor& desc, SelfType_t<data_t> value)
1227 198 : {
1228 198 : auto dc = DataContainer<data_t>(desc);
1229 198 : dc = value;
1230 198 : return dc;
1231 198 : }
1232 :
1233 : template <class data_t>
1234 : DataContainer<data_t> fulllike(const DataContainer<data_t>& dc, SelfType_t<data_t> value)
1235 4 : {
1236 4 : return full<data_t>(dc.getDataDescriptor(), value);
1237 4 : }
1238 :
1239 : template <class data_t>
1240 : DataContainer<data_t> empty(const DataDescriptor& desc)
1241 883 : {
1242 883 : return DataContainer<data_t>(desc);
1243 883 : }
1244 :
1245 : template <class data_t>
1246 : DataContainer<data_t> emptylike(const DataContainer<data_t>& dc)
1247 526 : {
1248 526 : return empty<data_t>(dc.getDataDescriptor());
1249 526 : }
1250 :
1251 : // ------------------------------------------
1252 : // explicit template instantiation
1253 : template class DataContainer<float>;
1254 : template class DataContainer<complex<float>>;
1255 : template class DataContainer<double>;
1256 : template class DataContainer<complex<double>>;
1257 : template class DataContainer<index_t>;
1258 :
1259 : template DataContainer<float> clip<float>(const DataContainer<float>& dc, float min, float max);
1260 : template DataContainer<double> clip<double>(const DataContainer<double>& dc, double min,
1261 : double max);
1262 :
1263 : template DataContainer<float> concatenate<float>(const DataContainer<float>&,
1264 : const DataContainer<float>&);
1265 : template DataContainer<double> concatenate<double>(const DataContainer<double>&,
1266 : const DataContainer<double>&);
1267 : template DataContainer<complex<float>>
1268 : concatenate<complex<float>>(const DataContainer<complex<float>>&,
1269 : const DataContainer<complex<float>>&);
1270 : template DataContainer<complex<double>>
1271 : concatenate<complex<double>>(const DataContainer<complex<double>>&,
1272 : const DataContainer<complex<double>>&);
1273 :
1274 : template void lincomb<float>(SelfType_t<float>, const DataContainer<float>&, SelfType_t<float>,
1275 : const DataContainer<float>&, DataContainer<float>&);
1276 : template void lincomb<double>(SelfType_t<double>, const DataContainer<double>&,
1277 : SelfType_t<double>, const DataContainer<double>&,
1278 : DataContainer<double>&);
1279 : template DataContainer<float> lincomb<float>(SelfType_t<float>, const DataContainer<float>&,
1280 : SelfType_t<float>, const DataContainer<float>&);
1281 : template DataContainer<double> lincomb<double>(SelfType_t<double>, const DataContainer<double>&,
1282 : SelfType_t<double>,
1283 : const DataContainer<double>&);
1284 :
1285 : #define ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, type) \
1286 : template DataContainer<value_type_of_t<type>> fn<type>(const DataContainer<type>&);
1287 :
1288 : #define ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET_TYPES(fn) \
1289 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, index_t); \
1290 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, float); \
1291 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, double); \
1292 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, complex<float>); \
1293 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET(fn, complex<double>);
1294 :
1295 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET_TYPES(cwiseAbs)
1296 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET_TYPES(real)
1297 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET_TYPES(imag)
1298 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET_TYPES(sign)
1299 :
1300 : #undef ELSA_INSTANTIATE_UNARY_TRANSFORMATION_REAL_RET
1301 :
1302 : #define ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, type) \
1303 : template DataContainer<type> fn<type>(const DataContainer<type>&);
1304 :
1305 : #define ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(fn) \
1306 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, index_t) \
1307 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, float) \
1308 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, double) \
1309 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, complex<float>) \
1310 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(fn, complex<double>)
1311 :
1312 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(fftShift)
1313 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(ifftShift)
1314 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(fftShift2D)
1315 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(ifftShift2D)
1316 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(exp)
1317 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(log)
1318 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(square)
1319 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(sq)
1320 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(sqrt)
1321 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_TYPES(materialize)
1322 :
1323 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(bessel_log_0, float)
1324 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(bessel_1_0, float)
1325 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(bessel_log_0, double)
1326 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION(bessel_1_0, double)
1327 :
1328 : #undef ELSA_INSTANTIATE_UNARY_TRANSFORMATION
1329 :
1330 : #define ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(fn, type) \
1331 : template DataContainer<type> fn<type>(const DataContainer<type>&, SelfType_t<type>);
1332 :
1333 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(minimum, index_t)
1334 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(minimum, float)
1335 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(minimum, double)
1336 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(minimum, complex<float>)
1337 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(minimum, complex<double>)
1338 :
1339 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(maximum, index_t)
1340 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(maximum, float)
1341 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(maximum, double)
1342 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(maximum, complex<float>)
1343 : ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX(maximum, complex<double>)
1344 :
1345 : #undef ELSA_INSTANTIATE_UNARY_TRANSFORMATION_MINMAX
1346 :
1347 : #define ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(fn, type) \
1348 : template DataContainer<value_type_of_t<std::common_type_t<type, type>>> fn<type, type>( \
1349 : const DataContainer<type>&, const DataContainer<type>&);
1350 :
1351 : #define ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(fn, type1, type2) \
1352 : template DataContainer<value_type_of_t<std::common_type_t<type1, type2>>> fn<type1, type2>( \
1353 : const DataContainer<type1>&, const DataContainer<type2>&); \
1354 : template DataContainer<value_type_of_t<std::common_type_t<type2, type1>>> fn<type2, type1>( \
1355 : const DataContainer<type2>&, const DataContainer<type1>&);
1356 :
1357 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMax, index_t)
1358 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMax, float)
1359 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMax, double)
1360 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMax, thrust::complex<float>)
1361 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMax, thrust::complex<double>)
1362 :
1363 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, index_t, float)
1364 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, index_t, double)
1365 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, index_t, thrust::complex<float>)
1366 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, index_t, thrust::complex<double>)
1367 :
1368 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, float, double)
1369 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, float, thrust::complex<float>)
1370 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, float, thrust::complex<double>)
1371 :
1372 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, double, thrust::complex<float>)
1373 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, double, thrust::complex<double>)
1374 :
1375 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMax, thrust::complex<float>,
1376 : thrust::complex<double>)
1377 :
1378 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMin, index_t)
1379 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMin, float)
1380 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMin, double)
1381 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMin, thrust::complex<float>)
1382 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_SINGLE(cwiseMin, thrust::complex<double>)
1383 :
1384 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, index_t, float)
1385 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, index_t, double)
1386 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, index_t, thrust::complex<float>)
1387 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, index_t, thrust::complex<double>)
1388 :
1389 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, float, double)
1390 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, float, thrust::complex<float>)
1391 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, float, thrust::complex<double>)
1392 :
1393 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, double, thrust::complex<float>)
1394 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, double, thrust::complex<double>)
1395 :
1396 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED(cwiseMin, thrust::complex<float>,
1397 : thrust::complex<double>)
1398 :
1399 : #undef ELSA_INSTANTIATE_BINARY_TRANSFORMATION_MIXED
1400 :
1401 : #define ELSA_INSTANTIATE_BINARY_TRANSFORMATION(fn, type) \
1402 : template DataContainer<type> fn<type>(const DataContainer<type>&, const DataContainer<type>&);
1403 :
1404 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator-, index_t)
1405 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator-, float)
1406 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator-, double)
1407 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator-, thrust::complex<float>)
1408 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator-, thrust::complex<double>)
1409 :
1410 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator/, index_t)
1411 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator/, float)
1412 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator/, double)
1413 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator/, thrust::complex<float>)
1414 : ELSA_INSTANTIATE_BINARY_TRANSFORMATION(operator/, thrust::complex<double>)
1415 :
1416 : #undef ELSA_INSTANTIATE_BINARY_TRANSFORMATION
1417 :
1418 : #define ELSA_INSTANTIATE_OPERATOR_MIXED(fn, dtype, stype) \
1419 : template DataContainer<std::common_type_t<dtype, stype>> fn<dtype, stype, void>( \
1420 : const DataContainer<dtype>&, const stype&); \
1421 : template DataContainer<std::common_type_t<stype, dtype>> fn<stype, dtype, void>( \
1422 : const stype&, const DataContainer<dtype>&);
1423 :
1424 : #define ELSA_INSTANTIATE_OPERATOR_MIXED_ALL(fn) \
1425 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, int) \
1426 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, index_t) \
1427 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, float) \
1428 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, double) \
1429 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, thrust::complex<float>) \
1430 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, index_t, thrust::complex<double>) \
1431 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, int) \
1432 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, index_t) \
1433 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, float) \
1434 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, double) \
1435 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, thrust::complex<float>) \
1436 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, float, thrust::complex<double>) \
1437 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, int) \
1438 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, index_t) \
1439 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, float) \
1440 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, double) \
1441 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, thrust::complex<float>) \
1442 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, double, thrust::complex<double>) \
1443 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, int) \
1444 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, index_t) \
1445 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, float) \
1446 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, double) \
1447 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, thrust::complex<float>) \
1448 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<float>, thrust::complex<double>) \
1449 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, int) \
1450 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, index_t) \
1451 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, float) \
1452 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, double) \
1453 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, thrust::complex<float>) \
1454 : ELSA_INSTANTIATE_OPERATOR_MIXED(fn, thrust::complex<double>, thrust::complex<double>)
1455 :
1456 : ELSA_INSTANTIATE_OPERATOR_MIXED_ALL(operator/)
1457 : ELSA_INSTANTIATE_OPERATOR_MIXED_ALL(operator-)
1458 :
1459 : #define ELSA_INSTANTIATE_AS_COMPLEX(type) \
1460 : template DataContainer<add_complex_t<type>> asComplex<type>(const DataContainer<type>&);
1461 :
1462 : ELSA_INSTANTIATE_AS_COMPLEX(index_t)
1463 : ELSA_INSTANTIATE_AS_COMPLEX(float)
1464 : ELSA_INSTANTIATE_AS_COMPLEX(double)
1465 : ELSA_INSTANTIATE_AS_COMPLEX(complex<float>)
1466 : ELSA_INSTANTIATE_AS_COMPLEX(complex<double>)
1467 :
1468 : #undef ELSA_INSTANTIATE_AS_COMPLEX
1469 :
1470 : #define ELSA_INSTANTIATE_FILL_FN(fn, type) \
1471 : template DataContainer<type> fn<type>(const DataDescriptor&);
1472 :
1473 : #define ELSA_INSTANTIATE_FILL_FN_TYPES(fn) \
1474 : ELSA_INSTANTIATE_FILL_FN(fn, index_t) \
1475 : ELSA_INSTANTIATE_FILL_FN(fn, float) \
1476 : ELSA_INSTANTIATE_FILL_FN(fn, double) \
1477 : ELSA_INSTANTIATE_FILL_FN(fn, complex<float>) \
1478 : ELSA_INSTANTIATE_FILL_FN(fn, complex<double>)
1479 :
1480 : ELSA_INSTANTIATE_FILL_FN_TYPES(empty)
1481 : ELSA_INSTANTIATE_FILL_FN_TYPES(zeros)
1482 : ELSA_INSTANTIATE_FILL_FN_TYPES(ones)
1483 :
1484 : #undef ELSA_INSTANTIATE_FILL_FN
1485 : #undef ELSA_INSTANTIATE_FILL_FN_TYPES
1486 :
1487 : #define ELSA_INSTANTIATE_FILL_LIKE_FN(fn, type) \
1488 : template DataContainer<type> fn<type>(const DataContainer<type>&);
1489 :
1490 : #define ELSA_INSTANTIATE_FILL_LIKE_FN_TYPES(fn) \
1491 : ELSA_INSTANTIATE_FILL_LIKE_FN(fn, index_t) \
1492 : ELSA_INSTANTIATE_FILL_LIKE_FN(fn, float) \
1493 : ELSA_INSTANTIATE_FILL_LIKE_FN(fn, double) \
1494 : ELSA_INSTANTIATE_FILL_LIKE_FN(fn, complex<float>) \
1495 : ELSA_INSTANTIATE_FILL_LIKE_FN(fn, complex<double>)
1496 :
1497 : ELSA_INSTANTIATE_FILL_LIKE_FN_TYPES(emptylike)
1498 : ELSA_INSTANTIATE_FILL_LIKE_FN_TYPES(zeroslike)
1499 : ELSA_INSTANTIATE_FILL_LIKE_FN_TYPES(oneslike)
1500 :
1501 : #undef ELSA_INSTANTIATE_FILL_LIKE_FN
1502 : #undef ELSA_INSTANTIATE_FILL_LIKE_FN_TYPES
1503 :
1504 : #define ELSA_INSTANTIATE_FULL_FN(type) \
1505 : template DataContainer<type> full<type>(const DataDescriptor&, SelfType_t<type>); \
1506 : template DataContainer<type> fulllike<type>(const DataContainer<type>&, SelfType_t<type>);
1507 :
1508 : #define ELSA_INSTANTIATE_FULL_FN_TYPES() \
1509 : ELSA_INSTANTIATE_FULL_FN(index_t) \
1510 : ELSA_INSTANTIATE_FULL_FN(float) \
1511 : ELSA_INSTANTIATE_FULL_FN(double) \
1512 : ELSA_INSTANTIATE_FULL_FN(complex<float>) \
1513 : ELSA_INSTANTIATE_FULL_FN(complex<double>)
1514 :
1515 : ELSA_INSTANTIATE_FULL_FN_TYPES()
1516 :
1517 : #undef ELSA_INSTANTIATE_FULL_FN
1518 : #undef ELSA_INSTANTIATE_FULL_FN_TYPES
1519 : #define ELSA_INSTANTIATE_RFFT_IRFFT(type) \
1520 : template DataContainer<complex<type>> rfft(const DataContainer<type>& dc, FFTNorm norm, \
1521 : FFTPolicy policy); \
1522 : template DataContainer<type> irfft(const DataContainer<complex<type>>& dc, FFTNorm norm, \
1523 : FFTPolicy policy);
1524 :
1525 : ELSA_INSTANTIATE_RFFT_IRFFT(float)
1526 : ELSA_INSTANTIATE_RFFT_IRFFT(double)
1527 :
1528 : #undef ELSA_INSTANTIATE_RFFT_IRFFT
1529 : } // namespace elsa
|