Line data Source code
1 : #include "PartitionDescriptor.h" 2 : #include "Error.h" 3 : #include "TypeCasts.hpp" 4 : 5 : #include <unordered_map> 6 : #include <type_traits> 7 : 8 : namespace elsa 9 : { 10 : PartitionDescriptor::PartitionDescriptor(const DataDescriptor& dataDescriptor, 11 : index_t numberOfBlocks) 12 : : BlockDescriptor{dataDescriptor}, 13 : _indexMap(numberOfBlocks), 14 : _blockDescriptors(0), 15 : _blockOffsets(numberOfBlocks) 16 1535 : { 17 1535 : if (numberOfBlocks < 2) 18 1 : throw InvalidArgumentError( 19 1 : "PartitionDescriptor: number of blocks must be greater than one"); 20 : 21 1534 : index_t lastDimSize = _numberOfCoefficientsPerDimension[_numberOfDimensions - 1]; 22 : 23 1534 : if (numberOfBlocks > lastDimSize) 24 1 : throw InvalidArgumentError( 25 1 : "PartitionDescriptor: number of blocks too large for given descriptor"); 26 : 27 1533 : index_t rest = lastDimSize % numberOfBlocks; 28 : 29 1533 : auto blockDesc = generateDescriptorOfPartition(lastDimSize / numberOfBlocks); 30 1533 : _blockDescriptors.push_back(std::move(blockDesc)); 31 1533 : _indexMap.head(numberOfBlocks - rest).setZero(); 32 71537 : for (index_t i = 0; i < numberOfBlocks && i <= numberOfBlocks - rest; i++) 33 70004 : _blockOffsets[i] = i * _blockDescriptors[0]->getNumberOfCoefficients(); 34 : 35 1533 : if (rest > 0) { 36 13 : blockDesc = generateDescriptorOfPartition(lastDimSize / numberOfBlocks + 1); 37 13 : _blockDescriptors.push_back(std::move(blockDesc)); 38 13 : _indexMap.tail(rest).array().setConstant(1); 39 13 : auto numCoeffs = _blockDescriptors[1]->getNumberOfCoefficients(); 40 62 : for (index_t i = numberOfBlocks - rest + 1; i < numberOfBlocks; i++) 41 49 : _blockOffsets[i] = _blockOffsets[i - 1] + numCoeffs; 42 13 : } 43 1533 : } 44 : 45 : PartitionDescriptor::PartitionDescriptor(const DataDescriptor& dataDescriptor, 46 : IndexVector_t slicesInBlock) 47 : : BlockDescriptor{dataDescriptor}, 48 : _indexMap(slicesInBlock.size()), 49 : _blockDescriptors(0), 50 : _blockOffsets(slicesInBlock.size()) 51 79 : { 52 79 : if (slicesInBlock.size() < 2) 53 1 : throw InvalidArgumentError( 54 1 : "PartitionDescriptor: number of blocks must be greater than one"); 55 : 56 78 : if ((slicesInBlock.array() <= 0).any()) 57 1 : throw InvalidArgumentError( 58 1 : "PartitionDescriptor: non-positive number of coefficients not allowed"); 59 : 60 77 : if (slicesInBlock.sum() != _numberOfCoefficientsPerDimension[_numberOfDimensions - 1]) 61 1 : throw InvalidArgumentError("PartitionDescriptor: cumulative size of partitioned " 62 1 : "descriptor does not match size of original descriptor"); 63 : 64 76 : std::unordered_map<index_t, index_t> sizeToIndex; 65 76 : _blockOffsets[0] = 0; 66 414 : for (index_t i = 0; i < getNumberOfBlocks(); i++) { 67 338 : auto it = sizeToIndex.find(slicesInBlock[i]); 68 338 : index_t numCoeffs; 69 : 70 338 : if (it != sizeToIndex.end()) { 71 208 : _indexMap[i] = it->second; 72 208 : auto index = asSigned(it->second); 73 208 : numCoeffs = _blockDescriptors[index]->getNumberOfCoefficients(); 74 208 : } else { 75 130 : sizeToIndex.insert({slicesInBlock[i], _blockDescriptors.size()}); 76 130 : _indexMap[i] = asUnsigned(_blockDescriptors.size()); 77 130 : _blockDescriptors.push_back(generateDescriptorOfPartition(slicesInBlock[i])); 78 130 : numCoeffs = _blockDescriptors.back()->getNumberOfCoefficients(); 79 130 : } 80 : 81 338 : if (i != getNumberOfBlocks() - 1) 82 262 : _blockOffsets[i + 1] = _blockOffsets[i] + numCoeffs; 83 338 : } 84 76 : } 85 : 86 : PartitionDescriptor::PartitionDescriptor(const PartitionDescriptor& other) 87 : : BlockDescriptor(other), _indexMap(other._indexMap), _blockOffsets{other._blockOffsets} 88 1663 : { 89 1663 : for (const auto& blockDesc : other._blockDescriptors) 90 1668 : _blockDescriptors.push_back(blockDesc->clone()); 91 1663 : } 92 : 93 5811 : index_t PartitionDescriptor::getNumberOfBlocks() const { return _indexMap.size(); } 94 : 95 : const DataDescriptor& PartitionDescriptor::getDescriptorOfBlock(index_t i) const 96 1741 : { 97 1741 : if (i < 0 || i >= getNumberOfBlocks()) 98 8 : throw InvalidArgumentError("BlockDescriptor: index i is out of bounds"); 99 : 100 1733 : auto index = asUnsigned(_indexMap[i]); 101 1733 : return *_blockDescriptors[index]; 102 1733 : } 103 : 104 : index_t PartitionDescriptor::getOffsetOfBlock(index_t i) const 105 1692 : { 106 1692 : if (i < 0 || i >= getNumberOfBlocks()) 107 4 : throw InvalidArgumentError("BlockDescriptor: index i is out of bounds"); 108 : 109 1688 : return _blockOffsets[i]; 110 1688 : } 111 : 112 : PartitionDescriptor* PartitionDescriptor::cloneImpl() const 113 1663 : { 114 1663 : return new PartitionDescriptor(*this); 115 1663 : } 116 : 117 : bool PartitionDescriptor::isEqual(const DataDescriptor& other) const 118 43 : { 119 43 : if (!BlockDescriptor::isEqual(other)) 120 11 : return false; 121 : 122 : // static cast as type checked in base comparison 123 32 : auto otherBlock = static_cast<const PartitionDescriptor*>(&other); 124 : 125 32 : return _blockOffsets == otherBlock->_blockOffsets; 126 32 : } 127 : 128 : std::unique_ptr<VolumeDescriptor> 129 : PartitionDescriptor::generateDescriptorOfPartition(index_t numberOfSlices) const 130 1676 : { 131 1676 : auto coeffsPerDim = getNumberOfCoefficientsPerDimension(); 132 1676 : coeffsPerDim[_numberOfDimensions - 1] = numberOfSlices; 133 1676 : return std::make_unique<VolumeDescriptor>(coeffsPerDim, getSpacingPerDimension()); 134 1676 : } 135 : } // namespace elsa