Line data Source code
1 : #include "DataContainer.h"
2 : #include "DataContainerFormatter.hpp"
3 : #include "FormatConfig.h"
4 : #include "DataHandlerCPU.h"
5 : #include "DataHandlerMapCPU.h"
6 : #include "BlockDescriptor.h"
7 : #include "RandomBlocksDescriptor.h"
8 : #include "PartitionDescriptor.h"
9 : #include "Error.h"
10 : #include "TypeCasts.hpp"
11 : #include "Assertions.h"
12 :
13 : #include <utility>
14 : #include <algorithm>
15 :
16 : namespace elsa
17 : {
18 :
19 : template <typename data_t>
20 0 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
21 : DataHandlerType handlerType)
22 0 : : _dataDescriptor{dataDescriptor.clone()},
23 0 : _dataHandler{createDataHandler(handlerType, _dataDescriptor->getNumberOfCoefficients())},
24 0 : _dataHandlerType{handlerType}
25 : {
26 0 : }
27 :
28 : template <typename data_t>
29 0 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
30 : const Eigen::Matrix<data_t, Eigen::Dynamic, 1>& data,
31 : DataHandlerType handlerType)
32 0 : : _dataDescriptor{dataDescriptor.clone()},
33 0 : _dataHandler{createDataHandler(handlerType, _dataDescriptor->getNumberOfCoefficients())},
34 0 : _dataHandlerType{handlerType}
35 : {
36 0 : if (_dataHandler->getSize() != data.size())
37 0 : throw InvalidArgumentError("DataContainer: initialization vector has invalid size");
38 :
39 0 : for (index_t i = 0; i < _dataHandler->getSize(); ++i)
40 0 : (*_dataHandler)[i] = data[i];
41 0 : }
42 :
43 : template <typename data_t>
44 0 : DataContainer<data_t>::DataContainer(const DataContainer<data_t>& other)
45 0 : : _dataDescriptor{other._dataDescriptor->clone()},
46 0 : _dataHandler{other._dataHandler->clone()},
47 0 : _dataHandlerType{other._dataHandlerType}
48 : {
49 0 : }
50 :
51 : template <typename data_t>
52 0 : DataContainer<data_t>& DataContainer<data_t>::operator=(const DataContainer<data_t>& other)
53 : {
54 0 : if (this != &other) {
55 0 : _dataDescriptor = other._dataDescriptor->clone();
56 :
57 0 : if (_dataHandler && canAssign(other._dataHandlerType)) {
58 0 : *_dataHandler = *other._dataHandler;
59 : } else {
60 0 : _dataHandler = other._dataHandler->clone();
61 0 : _dataHandlerType = other._dataHandlerType;
62 : }
63 : }
64 :
65 0 : return *this;
66 : }
67 :
68 : template <typename data_t>
69 0 : DataContainer<data_t>::DataContainer(DataContainer<data_t>&& other) noexcept
70 0 : : _dataDescriptor{std::move(other._dataDescriptor)},
71 0 : _dataHandler{std::move(other._dataHandler)},
72 0 : _dataHandlerType{std::move(other._dataHandlerType)}
73 : {
74 : // leave other in a valid state
75 0 : other._dataDescriptor = nullptr;
76 0 : other._dataHandler = nullptr;
77 0 : }
78 :
79 : template <typename data_t>
80 0 : DataContainer<data_t>& DataContainer<data_t>::operator=(DataContainer<data_t>&& other)
81 : {
82 0 : _dataDescriptor = std::move(other._dataDescriptor);
83 :
84 0 : if (_dataHandler && canAssign(other._dataHandlerType)) {
85 0 : *_dataHandler = std::move(*other._dataHandler);
86 : } else {
87 0 : _dataHandler = std::move(other._dataHandler);
88 0 : _dataHandlerType = std::move(other._dataHandlerType);
89 : }
90 :
91 : // leave other in a valid state
92 0 : other._dataDescriptor = nullptr;
93 0 : other._dataHandler = nullptr;
94 :
95 0 : return *this;
96 : }
97 :
98 : template <typename data_t>
99 0 : const DataDescriptor& DataContainer<data_t>::getDataDescriptor() const
100 : {
101 0 : return *_dataDescriptor;
102 : }
103 :
104 : template <typename data_t>
105 0 : index_t DataContainer<data_t>::getSize() const
106 : {
107 0 : return _dataHandler->getSize();
108 : }
109 :
110 : template <typename data_t>
111 0 : data_t& DataContainer<data_t>::operator[](index_t index)
112 : {
113 0 : ELSA_VERIFY(index >= 0);
114 0 : ELSA_VERIFY(index < getSize());
115 :
116 0 : return (*_dataHandler)[index];
117 : }
118 :
119 : template <typename data_t>
120 0 : const data_t& DataContainer<data_t>::operator[](index_t index) const
121 : {
122 0 : ELSA_VERIFY(index >= 0);
123 0 : ELSA_VERIFY(index < getSize());
124 :
125 0 : return static_cast<const DataHandler<data_t>&>(*_dataHandler)[index];
126 : }
127 :
128 : template <typename data_t>
129 0 : data_t DataContainer<data_t>::at(const IndexVector_t& coordinate) const
130 : {
131 0 : const auto arr = coordinate.array();
132 0 : if ((arr < 0).any()
133 0 : || (arr >= _dataDescriptor->getNumberOfCoefficientsPerDimension().array()).any()) {
134 0 : return 0;
135 : }
136 :
137 0 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
138 : }
139 :
140 : template <typename data_t>
141 0 : data_t& DataContainer<data_t>::operator()(const IndexVector_t& coordinate)
142 : {
143 : // const auto arr = coordinate.array();
144 : // const auto shape = _dataDescriptor->getNumberOfCoefficientsPerDimension().array();
145 : // ELSA_VERIFY((arr >= 0).all());
146 : // ELSA_VERIFY((arr < shape).all());
147 :
148 0 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
149 : }
150 :
151 : template <typename data_t>
152 0 : const data_t& DataContainer<data_t>::operator()(const IndexVector_t& coordinate) const
153 : {
154 : // const auto arr = coordinate.array();
155 : // const auto shape = _dataDescriptor->getNumberOfCoefficientsPerDimension().array();
156 : // ELSA_VERIFY((arr >= 0).all());
157 : // ELSA_VERIFY((arr < shape).all());
158 :
159 0 : return (*this)[_dataDescriptor->getIndexFromCoordinate(coordinate)];
160 : }
161 :
162 : template <typename data_t>
163 0 : data_t DataContainer<data_t>::dot(const DataContainer<data_t>& other) const
164 : {
165 0 : return _dataHandler->dot(*other._dataHandler);
166 : }
167 :
168 : template <typename data_t>
169 0 : GetFloatingPointType_t<data_t> DataContainer<data_t>::squaredL2Norm() const
170 : {
171 0 : return _dataHandler->squaredL2Norm();
172 : }
173 :
174 : template <typename data_t>
175 0 : GetFloatingPointType_t<data_t> DataContainer<data_t>::l2Norm() const
176 : {
177 0 : return _dataHandler->l2Norm();
178 : }
179 :
180 : template <typename data_t>
181 0 : index_t DataContainer<data_t>::l0PseudoNorm() const
182 : {
183 0 : return _dataHandler->l0PseudoNorm();
184 : }
185 :
186 : template <typename data_t>
187 0 : GetFloatingPointType_t<data_t> DataContainer<data_t>::l1Norm() const
188 : {
189 0 : return _dataHandler->l1Norm();
190 : }
191 :
192 : template <typename data_t>
193 0 : GetFloatingPointType_t<data_t> DataContainer<data_t>::lInfNorm() const
194 : {
195 0 : return _dataHandler->lInfNorm();
196 : }
197 :
198 : template <typename data_t>
199 0 : data_t DataContainer<data_t>::sum() const
200 : {
201 0 : return _dataHandler->sum();
202 : }
203 :
204 : template <typename data_t>
205 0 : data_t DataContainer<data_t>::minElement() const
206 : {
207 0 : return _dataHandler->minElement();
208 : }
209 :
210 : template <typename data_t>
211 0 : data_t DataContainer<data_t>::maxElement() const
212 : {
213 0 : return _dataHandler->maxElement();
214 : }
215 :
216 : template <typename data_t>
217 0 : void DataContainer<data_t>::fft(FFTNorm norm) const
218 : {
219 0 : this->_dataHandler->fft(*this->_dataDescriptor, norm);
220 0 : }
221 :
222 : template <typename data_t>
223 0 : void DataContainer<data_t>::ifft(FFTNorm norm) const
224 : {
225 0 : this->_dataHandler->ifft(*this->_dataDescriptor, norm);
226 0 : }
227 :
228 : template <typename data_t>
229 0 : DataContainer<data_t>& DataContainer<data_t>::operator+=(const DataContainer<data_t>& dc)
230 : {
231 0 : *_dataHandler += *dc._dataHandler;
232 0 : return *this;
233 : }
234 :
235 : template <typename data_t>
236 0 : DataContainer<data_t>& DataContainer<data_t>::operator-=(const DataContainer<data_t>& dc)
237 : {
238 0 : *_dataHandler -= *dc._dataHandler;
239 0 : return *this;
240 : }
241 :
242 : template <typename data_t>
243 0 : DataContainer<data_t>& DataContainer<data_t>::operator*=(const DataContainer<data_t>& dc)
244 : {
245 0 : *_dataHandler *= *dc._dataHandler;
246 0 : return *this;
247 : }
248 :
249 : template <typename data_t>
250 0 : DataContainer<data_t>& DataContainer<data_t>::operator/=(const DataContainer<data_t>& dc)
251 : {
252 0 : *_dataHandler /= *dc._dataHandler;
253 0 : return *this;
254 : }
255 :
256 : template <typename data_t>
257 0 : DataContainer<data_t>& DataContainer<data_t>::operator+=(data_t scalar)
258 : {
259 0 : *_dataHandler += scalar;
260 0 : return *this;
261 : }
262 :
263 : template <typename data_t>
264 0 : DataContainer<data_t>& DataContainer<data_t>::operator-=(data_t scalar)
265 : {
266 0 : *_dataHandler -= scalar;
267 0 : return *this;
268 : }
269 :
270 : template <typename data_t>
271 0 : DataContainer<data_t>& DataContainer<data_t>::operator*=(data_t scalar)
272 : {
273 0 : *_dataHandler *= scalar;
274 0 : return *this;
275 : }
276 :
277 : template <typename data_t>
278 0 : DataContainer<data_t>& DataContainer<data_t>::operator/=(data_t scalar)
279 : {
280 0 : *_dataHandler /= scalar;
281 0 : return *this;
282 : }
283 :
284 : template <typename data_t>
285 0 : DataContainer<data_t>& DataContainer<data_t>::operator=(data_t scalar)
286 : {
287 0 : *_dataHandler = scalar;
288 0 : return *this;
289 : }
290 :
291 : template <typename data_t>
292 : template <typename... Args>
293 : std::unique_ptr<DataHandler<data_t>>
294 0 : DataContainer<data_t>::createDataHandler(DataHandlerType handlerType, Args&&... args)
295 : {
296 0 : switch (handlerType) {
297 0 : case DataHandlerType::CPU:
298 0 : return std::make_unique<DataHandlerCPU<data_t>>(std::forward<Args>(args)...);
299 0 : case DataHandlerType::MAP_CPU:
300 0 : return std::make_unique<DataHandlerCPU<data_t>>(std::forward<Args>(args)...);
301 : #ifdef ELSA_CUDA_VECTOR
302 : case DataHandlerType::GPU:
303 : return std::make_unique<DataHandlerGPU<data_t>>(std::forward<Args>(args)...);
304 : case DataHandlerType::MAP_GPU:
305 : return std::make_unique<DataHandlerGPU<data_t>>(std::forward<Args>(args)...);
306 : #endif
307 0 : default:
308 0 : throw InvalidArgumentError("DataContainer: unknown handler type");
309 : }
310 : }
311 :
312 : template <typename data_t>
313 0 : DataContainer<data_t>::DataContainer(const DataDescriptor& dataDescriptor,
314 : std::unique_ptr<DataHandler<data_t>> dataHandler,
315 : DataHandlerType dataType)
316 0 : : _dataDescriptor{dataDescriptor.clone()},
317 0 : _dataHandler{std::move(dataHandler)},
318 0 : _dataHandlerType{dataType}
319 : {
320 0 : }
321 :
322 : template <typename data_t>
323 0 : bool DataContainer<data_t>::operator==(const DataContainer<data_t>& other) const
324 : {
325 0 : if (*_dataDescriptor != *other._dataDescriptor)
326 0 : return false;
327 :
328 0 : if (*_dataHandler != *other._dataHandler)
329 0 : return false;
330 :
331 0 : return true;
332 : }
333 :
334 : template <typename data_t>
335 0 : bool DataContainer<data_t>::operator!=(const DataContainer<data_t>& other) const
336 : {
337 0 : return !(*this == other);
338 : }
339 :
340 : template <typename data_t>
341 0 : DataContainer<data_t> DataContainer<data_t>::getBlock(index_t i)
342 : {
343 0 : const auto blockDesc = downcast_safe<BlockDescriptor>(_dataDescriptor.get());
344 0 : if (!blockDesc)
345 0 : throw LogicError("DataContainer: cannot get block from not-blocked container");
346 :
347 0 : if (i >= blockDesc->getNumberOfBlocks() || i < 0)
348 0 : throw InvalidArgumentError("DataContainer: block index out of bounds");
349 :
350 0 : index_t startIndex = blockDesc->getOffsetOfBlock(i);
351 0 : const auto& ithDesc = blockDesc->getDescriptorOfBlock(i);
352 0 : index_t blockSize = ithDesc.getNumberOfCoefficients();
353 :
354 0 : DataHandlerType newHandlerType = (_dataHandlerType == DataHandlerType::CPU
355 0 : || _dataHandlerType == DataHandlerType::MAP_CPU)
356 0 : ? DataHandlerType::MAP_CPU
357 : : DataHandlerType::MAP_GPU;
358 :
359 0 : return DataContainer<data_t>{ithDesc, _dataHandler->getBlock(startIndex, blockSize),
360 0 : newHandlerType};
361 : }
362 :
363 : template <typename data_t>
364 0 : const DataContainer<data_t> DataContainer<data_t>::getBlock(index_t i) const
365 : {
366 0 : const auto blockDesc = downcast_safe<BlockDescriptor>(_dataDescriptor.get());
367 0 : if (!blockDesc)
368 0 : throw LogicError("DataContainer: cannot get block from not-blocked container");
369 :
370 0 : if (i >= blockDesc->getNumberOfBlocks() || i < 0)
371 0 : throw InvalidArgumentError("DataContainer: block index out of bounds");
372 :
373 0 : index_t startIndex = blockDesc->getOffsetOfBlock(i);
374 0 : const auto& ithDesc = blockDesc->getDescriptorOfBlock(i);
375 0 : index_t blockSize = ithDesc.getNumberOfCoefficients();
376 :
377 0 : DataHandlerType newHandlerType = (_dataHandlerType == DataHandlerType::CPU
378 0 : || _dataHandlerType == DataHandlerType::MAP_CPU)
379 0 : ? DataHandlerType::MAP_CPU
380 : : DataHandlerType::MAP_GPU;
381 :
382 : // getBlock() returns a pointer to non-const DH, but that's fine as it gets wrapped in a
383 : // constant container
384 0 : return DataContainer<data_t>{ithDesc, _dataHandler->getBlock(startIndex, blockSize),
385 0 : newHandlerType};
386 : }
387 :
388 : template <typename data_t>
389 0 : DataContainer<data_t> DataContainer<data_t>::viewAs(const DataDescriptor& dataDescriptor)
390 : {
391 0 : if (dataDescriptor.getNumberOfCoefficients() != getSize())
392 0 : throw InvalidArgumentError("DataContainer: view must have same size as container");
393 :
394 0 : DataHandlerType newHandlerType = (_dataHandlerType == DataHandlerType::CPU
395 0 : || _dataHandlerType == DataHandlerType::MAP_CPU)
396 0 : ? DataHandlerType::MAP_CPU
397 : : DataHandlerType::MAP_GPU;
398 :
399 0 : return DataContainer<data_t>{dataDescriptor, _dataHandler->getBlock(0, getSize()),
400 0 : newHandlerType};
401 : }
402 :
403 : template <typename data_t>
404 : const DataContainer<data_t>
405 0 : DataContainer<data_t>::viewAs(const DataDescriptor& dataDescriptor) const
406 : {
407 0 : if (dataDescriptor.getNumberOfCoefficients() != getSize())
408 0 : throw InvalidArgumentError("DataContainer: view must have same size as container");
409 :
410 0 : DataHandlerType newHandlerType = (_dataHandlerType == DataHandlerType::CPU
411 0 : || _dataHandlerType == DataHandlerType::MAP_CPU)
412 0 : ? DataHandlerType::MAP_CPU
413 : : DataHandlerType::MAP_GPU;
414 :
415 : // getBlock() returns a pointer to non-const DH, but that's fine as it gets wrapped in a
416 : // constant container
417 0 : return DataContainer<data_t>{dataDescriptor, _dataHandler->getBlock(0, getSize()),
418 0 : newHandlerType};
419 : }
420 :
421 : template <typename data_t>
422 0 : const DataContainer<data_t> DataContainer<data_t>::slice(index_t i) const
423 : {
424 0 : auto& desc = getDataDescriptor();
425 0 : auto dim = desc.getNumberOfDimensions();
426 0 : auto sizeOfLastDim = desc.getNumberOfCoefficientsPerDimension()[dim - 1];
427 :
428 0 : if (i >= sizeOfLastDim) {
429 0 : throw LogicError("Trying to access out of bound slice");
430 : }
431 :
432 0 : if (sizeOfLastDim == 1) {
433 0 : return *this;
434 : }
435 :
436 0 : auto sliceDesc = PartitionDescriptor(desc, sizeOfLastDim);
437 :
438 : // Now set the slice
439 0 : return viewAs(sliceDesc).getBlock(i);
440 0 : }
441 :
442 : template <typename data_t>
443 0 : DataContainer<data_t> DataContainer<data_t>::slice(index_t i)
444 : {
445 0 : auto& desc = getDataDescriptor();
446 0 : auto dim = desc.getNumberOfDimensions();
447 0 : auto sizeOfLastDim = desc.getNumberOfCoefficientsPerDimension()[dim - 1];
448 :
449 0 : if (i >= sizeOfLastDim) {
450 0 : throw LogicError("Trying to access out of bound slice");
451 : }
452 :
453 0 : if (sizeOfLastDim == 1) {
454 0 : return *this;
455 : }
456 :
457 0 : auto sliceDesc = PartitionDescriptor(desc, sizeOfLastDim);
458 :
459 : // Now set the slice
460 0 : return viewAs(sliceDesc).getBlock(i);
461 0 : }
462 :
463 : template <typename data_t>
464 0 : typename DataContainer<data_t>::iterator DataContainer<data_t>::begin()
465 : {
466 0 : return iterator(&(*this)[0]);
467 : }
468 :
469 : template <typename data_t>
470 0 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::begin() const
471 : {
472 0 : return cbegin();
473 : }
474 :
475 : template <typename data_t>
476 0 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::cbegin() const
477 : {
478 0 : return const_iterator(&(*this)[0]);
479 : }
480 :
481 : template <typename data_t>
482 0 : typename DataContainer<data_t>::iterator DataContainer<data_t>::end()
483 : {
484 0 : return iterator(&(*this)[0] + getSize());
485 : }
486 :
487 : template <typename data_t>
488 0 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::end() const
489 : {
490 0 : return cend();
491 : }
492 :
493 : template <typename data_t>
494 0 : typename DataContainer<data_t>::const_iterator DataContainer<data_t>::cend() const
495 : {
496 0 : return const_iterator(&(*this)[0] + getSize());
497 : }
498 :
499 : template <typename data_t>
500 0 : typename DataContainer<data_t>::reverse_iterator DataContainer<data_t>::rbegin()
501 : {
502 0 : return reverse_iterator(end());
503 : }
504 :
505 : template <typename data_t>
506 0 : typename DataContainer<data_t>::const_reverse_iterator DataContainer<data_t>::rbegin() const
507 : {
508 0 : return crbegin();
509 : }
510 :
511 : template <typename data_t>
512 0 : typename DataContainer<data_t>::const_reverse_iterator DataContainer<data_t>::crbegin() const
513 : {
514 0 : return const_reverse_iterator(cend());
515 : }
516 :
517 : template <typename data_t>
518 0 : typename DataContainer<data_t>::reverse_iterator DataContainer<data_t>::rend()
519 : {
520 0 : return reverse_iterator(begin());
521 : }
522 :
523 : template <typename data_t>
524 0 : typename DataContainer<data_t>::const_reverse_iterator DataContainer<data_t>::rend() const
525 : {
526 0 : return crend();
527 : }
528 :
529 : template <typename data_t>
530 0 : typename DataContainer<data_t>::const_reverse_iterator DataContainer<data_t>::crend() const
531 : {
532 0 : return const_reverse_iterator(cbegin());
533 : }
534 :
535 : template <typename data_t>
536 0 : DataHandlerType DataContainer<data_t>::getDataHandlerType() const
537 : {
538 0 : return _dataHandlerType;
539 : }
540 :
541 : template <typename data_t>
542 0 : void DataContainer<data_t>::format(std::ostream& os, format_config cfg) const
543 : {
544 0 : DataContainerFormatter<data_t> fmt{cfg};
545 0 : fmt.format(os, *this);
546 0 : }
547 :
548 : template <typename data_t>
549 0 : DataContainer<data_t> DataContainer<data_t>::loadToCPU()
550 : {
551 0 : if (_dataHandlerType == DataHandlerType::CPU
552 0 : || _dataHandlerType == DataHandlerType::MAP_CPU) {
553 0 : throw LogicError(
554 : "DataContainer: cannot load data to CPU with already CPU based container");
555 : }
556 :
557 0 : DataContainer<data_t> dcCPU(*_dataDescriptor, DataHandlerType::CPU);
558 :
559 0 : for (index_t i = 0; i < getSize(); i++) {
560 0 : dcCPU[i] = this->operator[](i);
561 : }
562 :
563 0 : return dcCPU;
564 0 : }
565 :
566 : template <typename data_t>
567 0 : DataContainer<data_t> DataContainer<data_t>::loadToGPU()
568 : {
569 0 : if (_dataHandlerType == DataHandlerType::GPU
570 0 : || _dataHandlerType == DataHandlerType::MAP_GPU) {
571 0 : throw LogicError(
572 : "DataContainer: cannot load data to GPU with already GPU based container");
573 : }
574 :
575 0 : DataContainer<data_t> dcGPU(*_dataDescriptor, DataHandlerType::GPU);
576 :
577 0 : for (index_t i = 0; i < getSize(); i++) {
578 0 : dcGPU[i] = this->operator[](i);
579 : }
580 :
581 0 : return dcGPU;
582 0 : }
583 :
584 : template <typename data_t>
585 0 : bool DataContainer<data_t>::canAssign(DataHandlerType handlerType)
586 : {
587 0 : if (_dataHandlerType == DataHandlerType::CPU
588 0 : || _dataHandlerType == DataHandlerType::MAP_CPU) {
589 0 : switch (handlerType) {
590 0 : case DataHandlerType::CPU:
591 0 : return true;
592 : break;
593 0 : case DataHandlerType::MAP_CPU:
594 0 : return true;
595 : break;
596 0 : default:
597 0 : return false;
598 : }
599 : } else {
600 0 : switch (handlerType) {
601 0 : case DataHandlerType::GPU:
602 0 : return true;
603 : break;
604 0 : case DataHandlerType::MAP_GPU:
605 0 : return true;
606 : break;
607 0 : default:
608 0 : return false;
609 : }
610 : }
611 : }
612 :
613 : template <typename data_t>
614 0 : DataContainer<data_t> clip(DataContainer<data_t> dc, data_t min, data_t max)
615 : {
616 0 : std::transform(dc.begin(), dc.end(), dc.begin(), [&](auto x) {
617 0 : if (x < min) {
618 0 : return min;
619 0 : } else if (x > max) {
620 0 : return max;
621 : } else {
622 0 : return x;
623 : }
624 : });
625 :
626 0 : return dc;
627 : }
628 :
629 : template <typename data_t>
630 0 : DataContainer<data_t> concatenate(const DataContainer<data_t>& dc1,
631 : const DataContainer<data_t>& dc2)
632 : {
633 0 : auto desc1 = dc1.getDataDescriptor().clone();
634 0 : auto desc2 = dc2.getDataDescriptor().clone();
635 :
636 0 : if (desc1->getNumberOfDimensions() != desc2->getNumberOfDimensions()) {
637 0 : throw LogicError("Can't concatenate two DataContainers with different dimension");
638 : }
639 :
640 0 : std::vector<std::unique_ptr<DataDescriptor>> descriptors;
641 0 : descriptors.reserve(2);
642 0 : descriptors.push_back(std::move(desc1));
643 0 : descriptors.push_back(std::move(desc2));
644 :
645 0 : auto blockDesc = RandomBlocksDescriptor(descriptors);
646 0 : auto concatenated = DataContainer<data_t>(blockDesc);
647 :
648 0 : concatenated.getBlock(0) = dc1;
649 0 : concatenated.getBlock(1) = dc2;
650 0 : return concatenated;
651 0 : }
652 :
653 : template <typename data_t>
654 0 : DataContainer<data_t> fftShift2D(DataContainer<data_t> dc)
655 : {
656 0 : assert(dc.getDataDescriptor().getNumberOfDimensions() == 2
657 : && "DataContainer::fftShift2D: currently only supporting 2D signals");
658 :
659 0 : const DataDescriptor& dataDescriptor = dc.getDataDescriptor();
660 0 : IndexVector_t numOfCoeffsPerDim = dataDescriptor.getNumberOfCoefficientsPerDimension();
661 0 : index_t m = numOfCoeffsPerDim[0];
662 0 : index_t n = numOfCoeffsPerDim[1];
663 :
664 0 : index_t firstShift = m / 2;
665 0 : index_t secondShift = n / 2;
666 :
667 0 : DataContainer<data_t> copyDC(dataDescriptor);
668 :
669 0 : for (index_t i = 0; i < m; ++i) {
670 0 : for (index_t j = 0; j < n; ++j) {
671 0 : copyDC((i + firstShift) % m, (j + secondShift) % n) = dc(i, j);
672 : }
673 : }
674 :
675 0 : return copyDC;
676 0 : }
677 :
678 : template <typename data_t>
679 0 : DataContainer<data_t> ifftShift2D(DataContainer<data_t> dc)
680 : {
681 0 : assert(dc.getDataDescriptor().getNumberOfDimensions() == 2
682 : && "DataContainer::ifftShift2D: currently only supporting 2D signals");
683 :
684 0 : const DataDescriptor& dataDescriptor = dc.getDataDescriptor();
685 0 : IndexVector_t numOfCoeffsPerDim = dataDescriptor.getNumberOfCoefficientsPerDimension();
686 0 : index_t m = numOfCoeffsPerDim[0];
687 0 : index_t n = numOfCoeffsPerDim[1];
688 :
689 0 : index_t firstShift = -m / 2;
690 0 : index_t secondShift = -n / 2;
691 :
692 0 : DataContainer<data_t> copyDC(dataDescriptor);
693 :
694 0 : for (index_t i = 0; i < m; ++i) {
695 0 : for (index_t j = 0; j < n; ++j) {
696 0 : index_t leftIndex = (((i + firstShift) % m) + m) % m;
697 0 : index_t rightIndex = (((j + secondShift) % n) + n) % n;
698 0 : copyDC(leftIndex, rightIndex) = dc(i, j);
699 : }
700 : }
701 :
702 0 : return copyDC;
703 0 : }
704 :
705 : // ------------------------------------------
706 : // explicit template instantiation
707 : template class DataContainer<float>;
708 : template class DataContainer<complex<float>>;
709 : template class DataContainer<double>;
710 : template class DataContainer<complex<double>>;
711 : template class DataContainer<index_t>;
712 :
713 : template DataContainer<float> clip<float>(DataContainer<float> dc, float min, float max);
714 : template DataContainer<double> clip<double>(DataContainer<double> dc, double min, double max);
715 :
716 : template DataContainer<float> concatenate<float>(const DataContainer<float>&,
717 : const DataContainer<float>&);
718 : template DataContainer<double> concatenate<double>(const DataContainer<double>&,
719 : const DataContainer<double>&);
720 : template DataContainer<complex<float>>
721 : concatenate<complex<float>>(const DataContainer<complex<float>>&,
722 : const DataContainer<complex<float>>&);
723 : template DataContainer<complex<double>>
724 : concatenate<complex<double>>(const DataContainer<complex<double>>&,
725 : const DataContainer<complex<double>>&);
726 :
727 : template DataContainer<float> fftShift2D<float>(DataContainer<float>);
728 : template DataContainer<complex<float>>
729 : fftShift2D<complex<float>>(DataContainer<complex<float>>);
730 : template DataContainer<double> fftShift2D<double>(DataContainer<double>);
731 : template DataContainer<complex<double>>
732 : fftShift2D<complex<double>>(DataContainer<complex<double>>);
733 :
734 : template DataContainer<float> ifftShift2D<float>(DataContainer<float>);
735 : template DataContainer<complex<float>>
736 : ifftShift2D<complex<float>>(DataContainer<complex<float>>);
737 : template DataContainer<double> ifftShift2D<double>(DataContainer<double>);
738 : template DataContainer<complex<double>>
739 : ifftShift2D<complex<double>>(DataContainer<complex<double>>);
740 :
741 : } // namespace elsa
|