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