I have designed a class bunji::Tensor
which is a multi-dimensional array. I have designed it to have a similar interface to a multi-dimensional std::vector
, just that the bunji::Tensor
constructor takes in an std::vector
in its constructor which defines the dimensions, i.e.
bunji::Tensor<double, 3> my_tensor({10, 4, 2});
Creates a 3 dimensional tensor of doubles, with dimensions x=10
, y=4
, and z=2
.
I have made some tests for this tensor using the google/googletest
testing framework. My tests are below.
#include "tensor.hpp"
#include <gtest/gtest.h>
void test_manual_1d(const std::size_t x)
{
bunji::Tensor<int, 1> tensor({x});
for (std::size_t i = 0; i < x; ++i)
{
EXPECT_EQ(tensor[i], 0);
tensor[i] = i+1;
}
for (std::size_t i = 0; i < x; ++i)
{
EXPECT_EQ(tensor[i], i+1);
}
}
void test_manual_2d(const std::size_t x, const std::size_t y)
{
bunji::Tensor<int, 2> tensor({x, y});
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
EXPECT_EQ(tensor[i][j], 0);
tensor[i][j] = (i+1) * (j+1);
}
}
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
EXPECT_EQ(tensor[i][j], (i+1) * (j+1));
}
}
}
void test_manual_3d(const std::size_t x, const std::size_t y, const std::size_t z)
{
bunji::Tensor<int, 3> tensor({x, y, z});
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
for (std::size_t k = 0; k < z; ++k)
{
EXPECT_EQ(tensor[i][j][k], 0);
tensor[i][j][k] = (i+1) * (j+1) * (k+1);
}
}
}
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
for (std::size_t k = 0; k < z; ++k)
{
EXPECT_EQ(tensor[i][j][k], (i+1) * (j+1) * (k+1));
}
}
}
}
void test_manual_4d(const std::size_t x, const std::size_t y, const std::size_t z, const std::size_t v)
{
bunji::Tensor<int, 4> tensor({x, y, z, v});
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
for (std::size_t k = 0; k < z; ++k)
{
for (std::size_t l = 0; l < v; ++l)
{
EXPECT_EQ(tensor[i][j][k][l], 0);
tensor[i][j][k][l] = (i+1) * (j+1) * (k+1) * (l+1);
}
}
}
}
for (std::size_t i = 0; i < x; ++i)
{
for (std::size_t j = 0; j < y; ++j)
{
for (std::size_t k = 0; k < z; ++k)
{
for (std::size_t l = 0; l < v; ++l)
{
EXPECT_EQ(tensor[i][j][k][l], (i+1) * (j+1) * (k+1) * (l+1));
}
}
}
}
}
template<std::size_t Dimensions, class Callable>
void nd_for_loop(std::size_t begin, std::size_t end, Callable &&c)
{
for(size_t i = begin; i != end; ++i)
{
if constexpr(Dimensions == 1)
{
c(i);
}
else
{
auto bind_argument = [i, &c](auto... args)
{
c(i, args...);
};
nd_for_loop<Dimensions-1>(begin, end, bind_argument);
}
}
}
TEST(tensor, tensor_manual)
{
nd_for_loop<1>(0, 8500, test_manual_1d);
nd_for_loop<2>(0, 100, test_manual_2d);
nd_for_loop<3>(0, 24, test_manual_3d);
nd_for_loop<4>(0, 12, test_manual_4d);
}
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
tensor.hpp
? \$\endgroup\$std::vector
, and it isn't what I would like to be reviewed. \$\endgroup\$