Commit 56296a9e authored by David Frank's avatar David Frank
Browse files

Add support to concatenate two DataContainers

When two DataContainers are concatenated, a new one with a
RandomBlocksDescriptor is created, with the two original descriptors
as blocks.

Currently, only concatenation of containers of equal dimension is
allowed.
parent 4beea4e3
Pipeline #643343 passed with stages
in 23 minutes and 13 seconds
......@@ -2,6 +2,7 @@
#include "DataHandlerCPU.h"
#include "DataHandlerMapCPU.h"
#include "BlockDescriptor.h"
#include "RandomBlocksDescriptor.h"
#include "Error.h"
#include "TypeCasts.hpp"
......@@ -504,6 +505,30 @@ namespace elsa
}
}
template <typename data_t>
DataContainer<data_t> concatenate(const DataContainer<data_t>& dc1,
const DataContainer<data_t>& dc2)
{
auto desc1 = dc1.getDataDescriptor().clone();
auto desc2 = dc2.getDataDescriptor().clone();
if (desc1->getNumberOfDimensions() != desc2->getNumberOfDimensions()) {
throw LogicError("Can't concatenate two DataContainers with different dimension");
}
std::vector<std::unique_ptr<DataDescriptor>> descriptors;
descriptors.reserve(2);
descriptors.push_back(std::move(desc1));
descriptors.push_back(std::move(desc2));
auto blockDesc = RandomBlocksDescriptor(descriptors);
auto concatenated = DataContainer<data_t>(blockDesc);
concatenated.getBlock(0) = dc1;
concatenated.getBlock(1) = dc2;
return concatenated;
}
// ------------------------------------------
// explicit template instantiation
template class DataContainer<float>;
......@@ -512,4 +537,15 @@ namespace elsa
template class DataContainer<std::complex<double>>;
template class DataContainer<index_t>;
template DataContainer<float> concatenate<float>(const DataContainer<float>&,
const DataContainer<float>&);
template DataContainer<double> concatenate<double>(const DataContainer<double>&,
const DataContainer<double>&);
template DataContainer<std::complex<float>>
concatenate<std::complex<float>>(const DataContainer<std::complex<float>>&,
const DataContainer<std::complex<float>>&);
template DataContainer<std::complex<double>>
concatenate<std::complex<double>>(const DataContainer<std::complex<double>>&,
const DataContainer<std::complex<double>>&);
} // namespace elsa
......@@ -446,6 +446,11 @@ namespace elsa
bool canAssign(DataHandlerType handlerType);
};
/// Concatenate two DataContainers to one (requires copying of both)
template <typename data_t>
DataContainer<data_t> concatenate(const DataContainer<data_t>& dc1,
const DataContainer<data_t>& dc2);
/// User-defined template argument deduction guide for the expression based constructor
template <typename Source>
DataContainer(Source const& source) -> DataContainer<typename Source::data_t>;
......
......@@ -45,6 +45,12 @@ TYPE_TO_STRING(TestHelperCPU<index_t>);
TYPE_TO_STRING(TestHelperCPU<std::complex<float>>);
TYPE_TO_STRING(TestHelperCPU<std::complex<double>>);
TYPE_TO_STRING(DataContainer<float>);
TYPE_TO_STRING(DataContainer<double>);
TYPE_TO_STRING(DataContainer<index_t>);
TYPE_TO_STRING(DataContainer<std::complex<float>>);
TYPE_TO_STRING(DataContainer<std::complex<double>>);
#ifdef ELSA_CUDA_VECTOR
using GPUTypeTuple =
std::tuple<TestHelperGPU<float>, TestHelperGPU<double>, TestHelperGPU<std::complex<float>>,
......@@ -838,6 +844,131 @@ TEST_CASE("DataContainer: Testing iterators for DataContainer")
}
}
TEST_CASE_TEMPLATE("DataContainer: Concatenate two DataContainers", data_t, float, double,
std::complex<float>, std::complex<double>)
{
GIVEN("Two equally sized 1D data containers")
{
constexpr index_t size = 20;
IndexVector_t numCoeff(1);
numCoeff << size;
VolumeDescriptor desc(numCoeff);
Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size);
Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size);
DataContainer dc1(desc, randVec1);
DataContainer dc2(desc, randVec2);
auto concated = concatenate(dc1, dc2);
THEN("The size of the concatenated DataContainer is twice the original one")
{
REQUIRE_EQ(concated.getSize(), 2 * size);
}
THEN("The values correspond to the original DataContainers")
{
for (int i = 0; i < size; ++i) {
INFO("Error at position: ", i);
REQUIRE_EQ(concated[i], randVec1[i]);
}
for (int i = 0; i < size; ++i) {
INFO("Error at position: ", i + size);
REQUIRE_EQ(concated[i + size], randVec2[i]);
}
}
}
GIVEN("Two differently sized 1D data containers")
{
IndexVector_t numCoeff(1);
constexpr index_t size1 = 20;
numCoeff[0] = size1;
VolumeDescriptor desc1(numCoeff);
constexpr index_t size2 = 10;
numCoeff[0] = size2;
VolumeDescriptor desc2(numCoeff);
Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size1);
Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size2);
DataContainer dc1(desc1, randVec1);
DataContainer dc2(desc2, randVec2);
auto concated = concatenate(dc1, dc2);
THEN("The size of the concatenated DataContainer is twice the original one")
{
REQUIRE_EQ(concated.getSize(), size1 + size2);
}
THEN("The values correspond to the original DataContainers")
{
for (int i = 0; i < size1; ++i) {
INFO("Error at position: ", i);
REQUIRE_EQ(concated[i], randVec1[i]);
}
for (int i = 0; i < size2; ++i) {
INFO("Error at position: ", i + size1);
REQUIRE_EQ(concated[i + size1], randVec2[i]);
}
}
}
GIVEN("Two equally sized 2D data containers")
{
constexpr index_t size = 20;
IndexVector_t numCoeff(2);
numCoeff << size, size;
VolumeDescriptor desc(numCoeff);
Vector_t<data_t> randVec1 = Vector_t<data_t>::Random(size * size);
Vector_t<data_t> randVec2 = Vector_t<data_t>::Random(size * size);
DataContainer dc1(desc, randVec1);
DataContainer dc2(desc, randVec2);
auto concated = concatenate(dc1, dc2);
THEN("The size of the concatenated DataContainer is twice the original one")
{
REQUIRE_EQ(concated.getSize(), 2 * (size * size));
}
THEN("The values correspond to the original DataContainers")
{
for (int i = 0; i < size * size; ++i) {
INFO("Error at position: ", i);
REQUIRE_EQ(concated[i], randVec1[i]);
}
for (int i = 0; i < size * size; ++i) {
INFO("Error at position: ", i + size);
REQUIRE_EQ(concated[i + size * size], randVec2[i]);
}
}
}
GIVEN("DataContainers of different dimension")
{
IndexVector_t numCoeff1D(1);
numCoeff1D << 20;
VolumeDescriptor desc1D(numCoeff1D);
IndexVector_t numCoeff2D(2);
numCoeff2D << 20, 20;
VolumeDescriptor desc2D(numCoeff2D);
DataContainer dc1(desc1D);
DataContainer dc2(desc2D);
THEN("The concatenation throws") { REQUIRE_THROWS_AS(concatenate(dc1, dc2), LogicError); }
}
}
// "instantiate" the test templates for CPU types
TEST_CASE_TEMPLATE_APPLY(datacontainer_construction, CPUTypeTuple);
TEST_CASE_TEMPLATE_APPLY(datacontainer_reduction, CPUTypeTuple);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment