elsa projectors

Geometry

class elsa::Geometry

Class representing 2d/3d projective camera geometry for use in CT projectors.

The location of X-ray source, volume (typically containing the center of rotation), and X-ray detector are encoded using projection matrices (see A. Zissermann, “Multiple View Geometry in

Computer Vision”). Detectors are assumed to be flat.

Author

Matthias Wieczorek - initial code

Author

Maximilian Hornung - modularization, redesign

Author

David Frank - bugfixes, strong typing

Author

Nikola Dinev - refactoring

Author

Tobias Lasser - refactoring, modernization

Public Functions

Geometry(geometry::SourceToCenterOfRotation sourceToCenterOfRotation, geometry::CenterOfRotationToDetector centerOfRotationToDetector, geometry::Radian angle, geometry::VolumeData2D &&volData, geometry::SinogramData2D &&sinoData, geometry::PrincipalPointOffset offset = geometry::PrincipalPointOffset{0}, geometry::RotationOffset2D centerOfRotOffset = geometry::RotationOffset2D{0, 0})

Constructor for 2D projective geometry.

VolumeData2D and SinogramData2D are taken as r-value references, as it’s cheaper to move, them in, and they are only intended as temporary objects. o construct a

Geometry with VolumeData2D{…}/SinogramData2D{…} as temporary or move the object in, but be aware of reusing it
Parameters
  • [in] sourceToCenterOfRotation: distance from source to the center of rotation (along y axis)

  • [in] centerOfRotationToDetector: distance from center of rotation to detector (along y axis)

  • [in] angle: rotation angle (in radians)

  • [in] volData: descriptor for the 2d volume

  • [in] sinoData: descriptor for the sinogram

  • [in] offset: offset of the principal point [default 0]

  • [in] centerOfRotOffset: offset of the center of rotation

Geometry(geometry::SourceToCenterOfRotation sourceToCenterOfRotation, geometry::CenterOfRotationToDetector centerOfRotationToDetector, geometry::VolumeData3D &&volData, geometry::SinogramData3D &&sinoData, geometry::RotationAngles3D angles, geometry::PrincipalPointOffset2D offset = geometry::PrincipalPointOffset2D{0, 0}, geometry::RotationOffset3D centerOfRotOffset = geometry::RotationOffset3D{0, 0, 0})

Constructor for 3D projective geometry using Euler angles.

Alpha, beta, gamma are Euler rotation angles using the YZY convention. They are specified in radians. In standard circular trajectory CT settings, we would have alpha = beta = 0, while gamma is the angle of rotation)

Parameters
  • [in] sourceToCenterOfRotation: distance from source to the center of rotation (along z axis)

  • [in] centerOfRotationToDetector: distance from center of rotation to detector (along z axis)

  • [in] volData: descriptor for the 3d volume

  • [in] sinoData: descriptor for the sinogram

  • [in] angles: (gamma -> around y’’-axis, beta -> around z’ axis, alpha -> around y axis) in radians

  • [in] offset: offset of the principal point

  • [in] centerOfRotOffset: offset of the center of rotation

VolumeData3D and SinogramData3D are taken as r-value references, as it’s cheaper to move, them in, and they are only intended as temporary objects. So construct a Geometry with VolumeData3D{…}/SinogramData3D{…} as temporary or move the object in, but be aware of reusing it

Geometry(real_t sourceToCenterOfRotation, real_t centerOfRotationToDetector, IndexVector_t vol_shape, IndexVector_t det_shape, const RealMatrix_t &R, RealVector_t vol_spacing = RealVector_t::Ones(3), RealVector_t det_spacing = RealVector_t::Ones(2), real_t px = static_cast<real_t>(0.0), real_t py = static_cast<real_t>(0.0), real_t centerOfRotationOffsetX = static_cast<real_t>(0.0), real_t centerOfRotationOffsetY = static_cast<real_t>(0.0), real_t centerOfRotationOffsetZ = static_cast<real_t>(0.0))

Constructor for 3D projective geometry using a 3x3 rotation matrix.

Parameters
  • [in] sourceToCenterOfRotation: distance from source to the center of rotation (along z axis)

  • [in] centerOfRotationToDetector: distance from center of rotation to detector (along z axis)

  • [in] volumeDescriptor: descriptor for the 3d volume

  • [in] sinoDescriptor: descriptor for the sinogram

  • [in] R: a 3x3 rotation matrix

  • [in] px: offset of the principal point in x-direction [default 0]

  • [in] py: offset of the principal point in y-direction [default 0]

  • [in] centerOfRotationOffsetX: offset of the center of rotation in x direction [default 0]

  • [in] centerOfRotationOffsetY: offset of the center of rotation in y direction [default 0]

  • [in] centerOfRotationOffsetZ: offset of the center of rotation in z direction [default 0]

Geometry(geometry::VolumeData3D &&volData, geometry::SinogramData3D &&sinoData, const RealMatrix_t &R, const RealMatrix_t &t, const RealMatrix_t &K)

Constructor for 3D projective geometry using existing matrices.

Parameters
  • [in] volData: descriptor for the 3d volume

  • [in] sinoData: descriptor for the sinogram

  • [in] R: the rotation matrix

  • [in] t: the translation

  • [in] K: the intrinsic parameter

const RealMatrix_t &getProjectionMatrix() const

Return the projection matrix.

Return

projection matrix

const RealMatrix_t &getInverseProjectionMatrix() const

Return the inverse of the projection matrix.

Return

the inverse of the projection matrix

const RealVector_t &getCameraCenter() const

Return the camera center corresponding to the projection matrix.

Return

the camera center (as a coordinate vector)

const RealMatrix_t &getRotationMatrix() const

Return the rotation matrix corresponding to the projection matrix.

Return

the rotation matrix

real_t getSourceDetectorDistance() const

Return the distance between source and detector.

Return

the distance

const RealMatrix_t &getExtrinsicMatrix() const

Return the extrinsics matrix.

Return

the extrinsics matrix

const RealMatrix_t &getIntrinsicMatrix() const

Return the intrinsic matrix.

Return

the intrinsic matrix

const RealVector_t &getTranslationVector() const

Return the translation vector from volume space into camera space.

Return

the translation vector

index_t getDimension() const

Return the dimension of the geometry.

Return

the dimension of the geometry

bool operator==(const Geometry &other) const

comparison operator

Private Functions

void buildMatrices()

build the projection matrix, its inverse and the camera center

Private Members

index_t _objectDimension

the dimension of the object space / volume (either 2 or 3)

real_t _sdDistance

the distance between source and detector

RealMatrix_t _P

the projection matrix (= [_K|0] * [_R|_t] * _S)

RealMatrix_t _Pinv

the inverse of the projection matrix

RealMatrix_t _ext

the extrinsic matrix (= [_R|_t] * _S)

RealMatrix_t _K

the intrinsic parameters _K

RealMatrix_t _R

the rotation matrix

RealVector_t _t

the translation in object space

RealMatrix_t _S

the scaling in object space

RealVector_t _C

the camera center _C

BinaryMethod

template<typename data_t = real_t>
class elsa::BinaryMethod : public elsa::LinearOperator<real_t>

Operator representing the discretized X-ray transform in 2d/3d using a simplistic binary hit/miss method.

The volume is traversed along the rays as specified by the

Geometry. Each ray is traversed in a continguous fashion (i.e. along long voxel borders, not diagonally) and each traversed voxel is counted as a hit with weight 1.
Author

Tobias Lasser - initial code, modernization

Author

David Frank - rewrite and fixes

Author

Maximilian Hornung - modularization

Author

Nikola Dinev - fixes

Template Parameters
  • data_t: data type for the domain and range of the operator, defaulting to real_t

The geometry is represented as a list of projection matrices (see class Geometry), one for each acquisition pose.

Forward projection is accomplished using apply(), backward projection using applyAdjoint(). This projector is matched.

Warning: This method is not particularly accurate!

Public Functions

BinaryMethod(const VolumeDescriptor &domainDescriptor, const DetectorDescriptor &rangeDescriptor)

Constructor for the binary voxel traversal method.

The domain is expected to be 2 or 3 dimensional (volSizeX, volSizeY, [volSizeZ]), the range is expected to be matching the domain (detSizeX, [detSizeY], acqPoses).

Parameters
  • [in] domainDescriptor: describing the domain of the operator (the volume)

  • [in] rangeDescriptor: describing the range of the operator (the sinogram)

~BinaryMethod() override = default

default destructor

Protected Functions

BinaryMethod(const BinaryMethod<data_t>&) = default

default copy constructor, hidden from non-derived classes to prevent potential slicing

void applyImpl(const DataContainer<data_t> &x, DataContainer<data_t> &Ax) const override

apply the binary method (i.e. forward projection)

void applyAdjointImpl(const DataContainer<data_t> &y, DataContainer<data_t> &Aty) const override

apply the adjoint of the binary method (i.e. backward projection)

BinaryMethod<data_t> *cloneImpl() const override

implement the polymorphic clone operation

bool isEqual(const LinearOperator<data_t> &other) const override

implement the polymorphic comparison operation

Private Functions

template<bool adjoint>
void traverseVolume(const DataContainer<data_t> &vector, DataContainer<data_t> &result) const

the traversal routine (for both apply/applyAdjoint)

template<bool adjoint, int dim>
void doTraverseVolume(const DataContainer<data_t> &vector, DataContainer<data_t> &result) const

the traversal routine (for both apply/applyAdjoint) for a particular number of dimensions

Private Members

BoundingBox _boundingBox

the bounding box of the volume

DetectorDescriptor &_detectorDescriptor

Reference to DetectorDescriptor stored in LinearOperator.

VolumeDescriptor &_volumeDescriptor

Reference to VolumeDescriptor stored in LinearOperator.

SiddonsMethod

template<typename data_t>
class elsa::SiddonsMethod

Operator representing the discretized X-ray transform in 2d/3d using Siddon’s method.

The volume is traversed along the rays as specified by the Geometry. Each ray is traversed in a contiguous fashion (i.e. along long voxel borders, not diagonally) and each traversed voxel is counted as a hit with weight according to the length of the path of the ray through the voxel.

The geometry is represented as a list of projection matrices (see class Geometry), one for each acquisition pose.

Forward projection is accomplished using apply(), backward projection using applyAdjoint(). This projector is matched.

Author

David Frank - initial code, refactor to XrayProjector

Author

Nikola Dinev - modularization, fixes

Template Parameters
  • data_t: data type for the domain and range of the operator, defaulting to real_t

Public Functions

SiddonsMethod(const VolumeDescriptor &domainDescriptor, const DetectorDescriptor &rangeDescriptor)

Constructor for Siddon’s method traversal.

The domain is expected to be 2 or 3 dimensional (volSizeX, volSizeY, [volSizeZ]), the range is expected to be matching the domain (detSizeX, [detSizeY], acqPoses).

Parameters
  • [in] domainDescriptor: describing the domain of the operator (the volume)

  • [in] rangeDescriptor: describing the range of the operator (the sinogram)

~SiddonsMethod() override = default

default destructor

Protected Functions

SiddonsMethod(const SiddonsMethod<data_t>&) = default

default copy constructor, hidden from non-derived classes to prevent potential slicing

Private Functions

SiddonsMethod<data_t> *_cloneImpl() const

implement the polymorphic clone operation

bool _isEqual(const LinearOperator<data_t> &other) const

implement the polymorphic comparison operation

JosephsMethod

template<typename data_t>
class elsa::JosephsMethod

Operator representing the discretized X-ray transform in 2d/3d using Joseph’s method.

The volume is traversed along the rays as specified by the

Geometry. For interior voxels the sampling point is located in the middle of the two planes orthogonal to the main direction of the ray. For boundary voxels the sampling point is located at the center of the ray intersection with the voxel.
Author

Christoph Hahn - initial implementation

Author

Maximilian Hornung - modularization

Author

Nikola Dinev - fixes

Template Parameters
  • data_t: data type for the domain and range of the operator, defaulting to real_t

The geometry is represented as a list of projection matrices (see class Geometry), one for each acquisition pose.

Two modes of interpolation are available: NN (NearestNeighbours) takes the value of the pixel/voxel containing the point LINEAR performs linear interpolation for the nearest 2 pixels (in 2D) or the nearest 4 voxels (in 3D).

Forward projection is accomplished using apply(), backward projection using applyAdjoint(). This projector is matched.

Public Functions

JosephsMethod(const VolumeDescriptor &domainDescriptor, const DetectorDescriptor &rangeDescriptor)

Constructor for Joseph’s traversal method.

The domain is expected to be 2 or 3 dimensional (volSizeX, volSizeY, [volSizeZ]), the range is expected to be matching the domain (detSizeX, [detSizeY], acqPoses).

Parameters
  • [in] domainDescriptor: describing the domain of the operator (the volume)

  • [in] rangeDescriptor: describing the range of the operator (the sinogram)

  • [in] interpolation: enum specifying the interpolation mode

~JosephsMethod() = default

default destructor

Protected Functions

JosephsMethod(const JosephsMethod<data_t>&) = default

default copy constructor, hidden from non-derived classes to prevent potential slicing

Private Functions

void forward(const BoundingBox &aabb, const DataContainer<data_t> &x, DataContainer<data_t> &Ax) const

apply Joseph’s method (i.e. forward projection)

void backward(const BoundingBox &aabb, const DataContainer<data_t> &y, DataContainer<data_t> &Aty) const

apply the adjoint of Joseph’s method (i.e. backward projection)

JosephsMethod<data_t> *_cloneImpl() const

implement the polymorphic clone operation

bool _isEqual(const LinearOperator<data_t> &other) const

implement the polymorphic comparison operation

template<bool adjoint, int dim>
void traverseVolume(const BoundingBox &aabb, const DataContainer<data_t> &vector, DataContainer<data_t> &result) const

the traversal routine (for both apply/applyAdjoint)

Implementation Details

BoundingBox

Warning

doxygenstruct: Cannot find class “elsa::BoundingBox” in doxygen xml output for project “elsa” from directory: /var/lib/gitlab-runner/builds/RFzX5nBc_/0/tum-ciip/elsa/build/docs/xml

Intersection

Warning

doxygenclass: Cannot find class “elsa::Intersection” in doxygen xml output for project “elsa” from directory: /var/lib/gitlab-runner/builds/RFzX5nBc_/0/tum-ciip/elsa/build/docs/xml

TraverseAABB

template<int dim>
class elsa::TraverseAABB

Class implementing a voxel traversal of a volume (AABB) along a ray.

This traversal proceeds along “long” voxel edges, it will “jump diagonally” iff that “long” voxel edge has the same value along more than one dimension. The method is based on Xiao et al.: Efficient implementation of the 3D-DDA ray traversal algorithm on GPU and its application in radiation dose calculation.

Author

Tobias Lasser - initial code

Author

David Frank - major rewrite

Author

Maximilian Hornung - modularization

Author

Nikola Dinev - fixes

Public Functions

TraverseAABB(const BoundingBox &aabb, const RealRay_t &r, IndexArray_t<dim> productOfCoefficientsPerDimension)

Constructor for traversal, accepting bounding box and ray.

Parameters
  • [in] aabb: axis-aligned boundary box describing the volume

  • [in] r: the ray to be traversed

void updateTraverse()

Update the traverser status by taking the next traversal step.

real_t updateTraverseAndGetDistance()

Update the traverser status by taking the next traversal step, return the distance of step.

Return

the distance of the step taken

bool isInBoundingBox() const

Return whether the traversal is still in the bounding box.

Return

true if still in bounding box, false otherwise

IndexArray_t<dim> getCurrentVoxel() const

Return the current voxel in the bounding box.

Return

coordinate vector

index_t getCurrentIndex() const

Return the index that corresponds to the current position.

Private Functions

RealArray_t<dim> calculateAABBIntersections(const RealRay_t &r, const BoundingBox &aabb)

compute the entry and exit points of ray r with the volume (aabb)

void initStepDirection(const RealArray_t<dim> &rd)

setup the step directions (which is basically the sign of the ray direction rd)

void selectClosestVoxel(const RealArray_t<dim> &entryPoint)

select the closest voxel to the entry point

void initDelta(const RealArray_t<dim> &rd, const RealArray_t<dim> &EPS, const RealArray_t<dim> &MAX)

setup the step sizes considering the ray direction rd

void initT(const RealArray_t<dim> &rd, const RealArray_t<dim> &EPS, const RealArray_t<dim> &MAX, const RealArray_t<dim> &entryPoint)

setup the maximum step parameters considering the ray direction rd

bool isCurrentPositionInAABB() const

check if the current index is still in the bounding box

void calcMask()

calculate the mask which masks out all but the minimal coefficients in _T.

void initCurrentIndex()

compute the index that corresponds to the initial position

void updateCurrentIndex()

compute the index that corresponds to the current position

Private Members

IndexArray_t<dim> _stepDirection

the step direction of the traverser

RealArray_t<dim> _currentPos

the current position of the traverser in the aabb

RealArray_t<dim> _T

the current maximum step parameter along the ray

RealArray_t<dim> _tDelta

the step sizes for the step parameter along the ray

bool _isInAABB = {false}

flag if traverser still in bounding box

real_t _tExit = {0.0}

the current step parameter exiting the current voxel

BooleanArray_t<dim> _mask

the current mask, with true for the directions in which we are stepping, and else fals

RealArray_t<dim> _aabbMin

result of aabb.min(), the lower corner of the aabb

RealArray_t<dim> _aabbMax

result of aabb.max(), the upper corner of the aabb

IndexArray_t<dim> _productOfCoefficientsPerDimension

the product of coefficients per dimension

index_t _currentIndex

the current index which corresponds to the current position

TraverseAABBJosephsMethod

Warning

doxygenclass: Cannot find class “elsa::TraverseAABBJosephsMethod” in doxygen xml output for project “elsa” from directory: /var/lib/gitlab-runner/builds/RFzX5nBc_/0/tum-ciip/elsa/build/docs/xml

SliceTraversal

class TransformToTraversal

Represent a transformation, which will transform any point into the traversal coordinate system.

In the traversal coordinate system, the reference direction - form which it is constructed - is transformed, such that the leading coefficient (i.e. the coefficient of largest absolute value), is in the positive x-direction (i.e. the first component)

The algorithm to determine the rotation in a 2D case is quite simple: Given the vector $\begin{bmatrix} x & y \end{bmatrix}$, first determine the leading axis, by finding the index of the component with maximum absolute value, i.e. $\text{axis} = \text{maxAxis} (\lvert x \rvert, \lvert y \rvert) $ (in this case, the max returns “x”, or “y” for our use cases instead of the actual value). Assume axis is either "x" or "y" and leadingCoeff stores corresponding value to the leading axis (but it’s signed!). Then in pseudocode the algorithm determines the rotation the following way:

if axis == "x" and maxCoeff >= 0:
    return rotate_by(0)
elif axis == "x" and maxCoeff <= 0:
    return rotate_by(180)
elif axis == "y" and maxCoeff >= 0:
    return rotate_by(90)
elif axis == "y" and maxCoeff <= 0:
    return rotate_by(270)

To extent it to 3D one further decision has to be made, do we only rotate, such that the leading direction is in the x direction, or do we rotate, such that y is the second largest direction and z is the smallest.

TODO: It might be nice to move this to a separate file and module, to wrap some of Eigens transformation stuff, such that it’s usable for dynamic cases, as we have here. This might be nice to have for the Geometry class as well, but not for now.

class elsa::SliceTraversal

Traverse a volume along the direction of a given ray. Each step it will advance one slice further in the direction of the ray. The traversal visits voxels at the center planes, i.e. it always evaluates at the center of voxel in the plane of leading direction.

This is a slightly modified version of the algorithm of Amanatides & Woo’s “A Fast Voxel

Traversal Algorithm”. The reference visits each and every single voxel along the ray. However, for this case we don’t need that.

Given a bounding box of the volume and a ray to traverse the volume, one can simply call:

for(auto [pos, voxel, t] = SliceTraversal(aabb, ray)) {
    // pos: exact position on center plane of voxel
    // voxel: current voxel
    // t: position on the ray (i.e. pos = ray.origin() + t * ray.direction())
}

The number of visited voxels is known at construction, therefore moving along the ray is basically decrementing a count. However, to return useful information, more bookkeeping is needed.

Dereferencing the iterator will return a small struct, which has information about the current position in the volume, the current voxel and the t parameter of the ray.

Note: When using voxel returned from iterating over the volume, it can happen that voxel on the boundary of the volume are returned. This can trigger wrong behaviour for certain applications and therefore should be handled with care.

A note about the implementation: To ease the construction and handling, the incoming ray and bounding box are transformed to a traversal internal coordinate space, in which the leading direction lies in the positive x-axis. The ‘world’ space is partitioned in 4 quadrants based on the direction. The first ranges for all direction from with a polar angle in the range of [-45°, 45°], the second (45°, 135°), the third [135°, 225°], and the fourth (225°, 315°). Note that -45° = 315°.

TODO:

  • Make the iterator random access

Author

  • David Frank - initial code

Public Functions

SliceTraversal() = delete

Delete default construction.

SliceTraversal(BoundingBox aabb, RealRay_t ray)

Construct traversal from bounding box and ray.

Iter begin() const

Get the first visited voxel.

Iter end() const

Get on past the end.

index_t startIndex() const

Get the index of the first visited voxel.

index_t endIndex() const

Get the index of the one past the last visited voxel.

index_t leadingDirection() const

Get the leading direction of the ray.

real_t t() const

Get the initial computed t value for the entry point.

real_t tDelta() const

Get the computed delta t value.

Private Members

index_t startIndex_ = {0}

TODO: Do we want to consider points that spawn inside the volume?

real_t t_ = {0.0}

t value for the first intersection of the ray and the bounding box

real_t tDelta_ = {0.0}

t value to increment each iteration

struct Iter

Traversal iterator, models forward iterator, maybe this should actually be an input iterator due to the non reference type of the dereference type. IDK, as we use it, this works, but in the future this might should be different.

Public Functions

Iter(index_t pos, const RealVector_t &entry, const RealVector_t &dir)

Construct iterator

Parameters
  • pos: index position of the traversal, used mainly for comparing two iterators

  • ray: traversed ray used to compute exact position on dereference

  • deltat: increment of t each increment

  • t: position along the ray

value_type operator*() const

Dereference iterator.

Iter &operator++()

Pre increment.

Iter operator++(int)

Post increment.

Friends

friend bool operator==(const Iter &lhs, const Iter &rhs)

Equal to operator with iterator.

friend bool operator!=(const Iter &lhs, const Iter &rhs)

Not equal to operator with iterator.

SubsetSampler

template<typename DetectorDescriptor_t, typename data_t = real_t>
class elsa::SubsetSampler : public elsa::Cloneable<SubsetSampler<DetectorDescriptor_t, real_t>>

Class representing a subset sampling method.

Author

Michael Loipführer - initial code

Template Parameters
  • DetectorDescriptor_t:

  • data_t: data type for the domain and range of the problem, defaulting to real_t

Public Types

enum SamplingStrategy

enum to differentiate between different subset sampling strategies

Values:

enumerator ROUND_ROBIN
enumerator ROTATIONAL_CLUSTERING

(default) divides data points into subsets via simple round-robin

Public Functions

SubsetSampler(const VolumeDescriptor &volumeDescriptor, const DetectorDescriptor_t &detectorDescriptor, index_t nSubsets, SamplingStrategy samplingStrategy = SamplingStrategy::ROUND_ROBIN)

Constructor for SubsetSampler.

Parameters
  • [in] volumeDescriptor: of the problem

  • [in] detectorDescriptor: describes the geometry and trajectory of the measurements

  • [in] nSubsets: is number of subsets that should be generated

  • [in] samplingStrategy: the strategy with which to sample the subsets

~SubsetSampler() = default

default destructor

DataContainer<data_t> getPartitionedData(const DataContainer<data_t> &sinogram)

return a new DataContainer with a BlockDescriptor containing the reordered sinogram data in each block corresponding to a subset

Parameters
  • [in] sinogram: the original sinogram

template<typename Projector_t>
std::unique_ptr<LinearOperator<data_t>> getProjector()

return

Template Parameters
  • projector_t: the type of projector to instantiate

template<typename Projector_t>
std::vector<std::unique_ptr<LinearOperator<data_t>>> getSubsetProjectors()

return a list of projectors that correspond to each subset

Template Parameters
  • projector_t: the type of projector to instantiate

Public Static Functions

std::vector<std::vector<index_t>> splitRoundRobin(const std::vector<index_t> &indices, index_t nSubsets)

Helper method implementing a general round robin splitting of a list of indices.

Return

mapping of data indices to subsets

std::vector<std::vector<index_t>> splitRotationalClustering(const DetectorDescriptor_t &detectorDescriptor, index_t nSubsets)

Helper method implementing rotational distance based sampling. Iteratively loop through all data points and assign the closest on based on the angle of rotation to the next subset.

Return

mapping of data indices to subsets

Protected Functions

SubsetSampler(const SubsetSampler<DetectorDescriptor_t, data_t> &other)

default copy constructor for cloning

bool isEqual(const SubsetSampler<DetectorDescriptor_t, data_t> &other) const override

implement the polymorphic comparison operation

SubsetSampler<DetectorDescriptor_t, data_t> *cloneImpl() const override

implement the polymorphic clone operation

Private Members

std::vector<std::vector<index_t>> _indexMapping

mapping of data point indices to respective subsets

VolumeDescriptor _volumeDescriptor

volume descriptor of the problem

DetectorDescriptor_t _fullDetectorDescriptor

the full detector descriptor of the problem

std::vector<DetectorDescriptor_t> _detectorDescriptors

list of detector descriptors corresponding to each block

index_t _nSubsets

number of subsets