[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/xtensor-stack/xtensor/master/test/test_xiterator.cpp [Back]  [Original]

/***************************************************************************
 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
 * Copyright (c) QuantStack                                                 *
 *                                                                          *
 * Distributed under the terms of the BSD 3-Clause License.                 *
 *                                                                          *
 * The full license is in the file LICENSE, distributed with this software. *
 ****************************************************************************/

#include "xtensor/containers/xarray.hpp"
#include "xtensor/containers/xtensor.hpp"

#include "test_common.hpp"
#include "test_common_macros.hpp"

namespace xt
{
    template 
    class xiterator_test : public ::testing::Test
    {
    public:

        using result_type = R;
    };

    using std::size_t;

    template 
    void test_increment(const R& result, const S& shape)
    {
        using size_type = typename R::size_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        auto offset = shape.size() - a.dimension();
        auto broadcasting_stride = std::accumulate(
            shape.cbegin(),
            shape.cbegin() + offset,
            size_type(1),
            std::multiplies()
        );
        size_type nb_inc =
            (L == layout_type::row_major
                 ? shape.back() * shape[shape.size() - 2] + 1
                 : broadcasting_stride * (result.shape().front() * result.shape()[1] + 1));

        int expected = a(1, 0, 1);

        auto iter = a.template begin(shape);
        auto iter2 = a.template begin(shape);
        for (size_type i = 0; i < nb_inc; ++i)
        {
            ++iter;
            iter2++;
        }

        CHECK_MESSAGE(*iter == expected, "preincrement operator doesn't give expected result");
        CHECK_MESSAGE(*iter2 == expected, "postincrement operator doesn't give expected result");
    }

    template 
    void test_random_increment(const R& result, const S& shape)
    {
        using difference_type = typename R::difference_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        auto offset = shape.size() - a.dimension();
        auto broadcasting_stride = std::accumulate(
            shape.cbegin(),
            shape.cbegin() + offset,
            difference_type(1),
            std::multiplies()
        );
        auto nb_inc = L == layout_type::row_major
                          ? difference_type(shape.back() * shape[shape.size() - 2] + 1)
                          : broadcasting_stride
                                * difference_type(result.shape().front() * result.shape()[1] + 1);

        int expected = a(1, 0, 1);

        auto iter = a.template begin();
        auto iter2 = a.template begin();

        iter += nb_inc;
        auto iter3 = iter2 + nb_inc;


        CHECK_MESSAGE(*iter == expected, "preincrement operator doesn't give expected result");
        CHECK_MESSAGE(*iter3 == expected, "postincrement operator doesn't give expected result");
        CHECK_MESSAGE(iter2[nb_inc] == expected, "postincrement operator doesn't give expected result");
    }

    template 
    void test_end(const R& result, const S& shape)
    {
        using size_type = typename R::size_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        size_type size = compute_size(shape);
        auto iter = a.template begin(shape);
        auto last = a.template end(shape);
        for (size_type i = 0; i < size; ++i)
        {
            ++iter;
        }

        CHECK_MESSAGE(iter == last, "iterator doesn't reach the end");
        EXPECT_FALSE(iter < last);
    }

    template 
    void test_decrement(const R& result, const S& shape)
    {
        using size_type = typename R::size_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        auto offset = shape.size() - a.dimension();
        auto broadcasting_stride = std::accumulate(
            shape.cbegin(),
            shape.cbegin() + offset,
            size_type(1),
            std::multiplies()
        );
        size_type nb_inc =
            (L == layout_type::row_major
                 ? shape.back() * shape[shape.size() - 2] + 1
                 : broadcasting_stride * (result.shape().front() * result.shape()[1] + 1));

        int expected = a(1, 1, 2);

        auto iter = a.template rbegin(shape);
        auto iter2 = a.template rbegin(shape);
        for (size_type i = 0; i < nb_inc; ++i)
        {
            ++iter;
            iter2++;
        }
        CHECK_MESSAGE(*iter == expected, "predecrement operator doesn't give expected result");
        CHECK_MESSAGE(*iter2 == expected, "postdecrement operator doesn't give expected result");
    }

    template 
    void test_random_decrement(const R& result, const S& shape)
    {
        using difference_type = typename R::difference_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        auto offset = shape.size() - a.dimension();
        auto broadcasting_stride = std::accumulate(
            shape.cbegin(),
            shape.cbegin() + offset,
            difference_type(1),
            std::multiplies()
        );

        auto nb_inc = L == layout_type::row_major
                          ? difference_type(shape.back() * shape[shape.size() - 2] + 1)
                          : broadcasting_stride
                                * difference_type(result.shape().front() * result.shape()[1] + 1);

        int expected = a(1, 1, 2);

        auto iter = a.template rbegin(shape);
        auto iter2 = a.template rbegin(shape);

        iter += nb_inc;
        auto iter3 = iter2 + nb_inc;

        CHECK_MESSAGE(*iter == expected, "predecrement operator doesn't give expected result");
        CHECK_MESSAGE(*iter3 == expected, "postdecrement operator doesn't give expected result");
    }

    template 
    void test_rend(const R& result, const S& shape)
    {
        using size_type = typename R::size_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        size_type size = compute_size(shape);
        auto iter = a.template rbegin(shape);
        auto last = a.template rend(shape);

        CHECK_MESSAGE(*iter == data.back(), "dereferencing rbegin does not result in last element");
        CHECK_MESSAGE(*last == data.front(), "dereferencing rend does not result in first element");

        for (size_type i = 0; i < size; ++i)
        {
            ++iter;
        }

        CHECK_MESSAGE(iter == last, "reverse iterator doesn't reach the end");
    }

#define XITERATOR_TEST_TYPES \
    row_major_result, column_major_result, central_major_result, unit_shape_result

    TEST_SUITE("xiterator_test")
    {
        TEST_CASE_TEMPLATE("increment", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_increment(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_increment(rm, rm.shape());
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_increment(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_increment(rm, rm.shape());
            }
        }


        TEST_CASE_TEMPLATE("random_increment", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_random_increment(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_random_increment(rm, rm.shape());
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_random_increment(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_random_increment(rm, rm.shape());
            }
        }


        TEST_CASE_TEMPLATE("end", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_end(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_end(rm, sh);
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_end(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_end(rm, sh);
            }
        }


        TEST_CASE_TEMPLATE("decrement", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_decrement(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_decrement(rm, sh);
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_decrement(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_decrement(rm, sh);
            }
        }

        TEST_CASE_TEMPLATE("random_decrement", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_random_decrement(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_random_decrement(rm, sh);
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_random_decrement(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_random_decrement(rm, sh);
            }
        }


        TEST_CASE_TEMPLATE("reverse_end", TypeParam, XITERATOR_TEST_TYPES)
        {
            using TestFixture = xiterator_test;
            typename TestFixture::result_type rm;
            SUBCASE("same shape - row_major iterator")
            {
                test_rend(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - row_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_rend(rm, sh);
            }

            SUBCASE("same shape - column_major iterator")
            {
                test_rend(rm, rm.shape());
            }

            SUBCASE("broadcasting shape - column_major iterator")
            {
                layout_result::shape_type sh = rm.shape();
                sh.insert(sh.begin(), 2);
                sh.insert(sh.begin(), 4);
                test_rend(rm, sh);
            }
        }
    }

    template 
    void test_minus(const R& result, const S& shape)
    {
        using size_type = typename R::size_type;
        using difference_type = typename R::difference_type;
        using vector_type = typename R::vector_type;
        vector_type data = result.storage();
        xarray_adaptor a(data, result.shape(), result.strides());

        size_type size = shape.size();
        difference_type nb_inc = difference_type(
            L == layout_type::row_major ? shape.back() * shape[size - 2] + shape.back() + 2
                                        : shape[size - 3] * shape[size - 2] * 2 + shape[size - 3] + 1
        );
        difference_type nb_inc2 = difference_type(
            L == layout_type::row_major ? shape.back() * shape[size - 2] * 2 + 3
                                        : shape[size - 3] * shape[size - 2] * 3 + 2
        );

        ptrdiff_t expected = ptrdiff_t(nb_inc2 - nb_inc);

        auto iter = a.template begin() + nb_inc;
        auto iter2 = a.template begin() + nb_inc2;
        CHECK_MESSAGE(iter2 - iter == expected, "operator- doesn't give expected result");

        auto riter = a.template rbegin() + nb_inc;
        auto riter2 = a.template rbegin() + nb_inc2;
        CHECK_MESSAGE(riter2 - riter == expected, "operator- doesn't give expected result");

        auto diff = a.template end() - a.template begin();
        CHECK_EQ(size_type(diff), a.size());

        auto rdiff = a.template rend() - a.template rbegin();
        CHECK_EQ(size_type(rdiff), a.size());
    }

    TEST(xiterator, row_major_minus)
    {
        row_major_result rm;
        SUBCASE("same shape - row_major iterator")
        {
            test_minus(rm, rm.shape());
        }

        SUBCASE("broadcasting shape - row_major iterator")
        {
            layout_result::shape_type sh = rm.shape();
            sh.insert(sh.begin(), 2);
            sh.insert(sh.begin(), 4);
            test_minus(rm, rm.shape());
        }
    }

    TEST(xiterator, column_major_minus)
    {
        column_major_result rm;
        SUBCASE("same shape - column_major iterator")
        {
            test_minus(rm, rm.shape());
        }

        SUBCASE("broadcasting shape - column_major iterator")
        {
            layout_result::shape_type sh = rm.shape();
            sh.insert(sh.begin(), 2);
            sh.insert(sh.begin(), 4);
            test_minus(rm, rm.shape());
        }
    }

    TEST(xiterator, broadcast)
    {
        EXPECT_TRUE(broadcastable(std::vector({1, 2, 1}), std::vector({3, 2, 1})));
        EXPECT_TRUE(broadcastable(std::vector({1, 1}), std::vector({3, 2, 1})));
        EXPECT_TRUE(broadcastable(std::vector({1, 1}), std::vector({2, 2, 1})));
        EXPECT_FALSE(broadcastable(std::vector({2, 2, 1}), std::vector({3, 2, 1})));
    }

    TEST(xiterator, pointer)
    {
        xarray m{{3, 4}, {6, 5}};
        constexpr layout_type l = xarray::static_layout == layout_type::column_major
                                      ? layout_type::row_major
                                      : layout_type::column_major;
        auto it = m.begin();
        EXPECT_EQ(*(it.operator->()), 3);
    }

    TEST(xiterator, cross_layout)
    {
        xarray a = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
        xarray b = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};

        // Performs an element-wise comparison via iterators and ensures the default traversal
        // of a container is consistent for any layout.
        bool res = (a == b);
        EXPECT_TRUE(res);
    }

    TEST(xiterator, comparisons)
    {
        row_major_result rm;
        xarray arr(rm.shape());

        auto rm_iter = arr.template cbegin();
        auto rm_iter2 = rm_iter + 2;

        EXPECT_TRUE(rm_iter != rm_iter2);
        EXPECT_FALSE(rm_iter == rm_iter2);
        EXPECT_TRUE(rm_iter < rm_iter2);
        EXPECT_TRUE(rm_iter  rm_iter2);
        EXPECT_FALSE(rm_iter >= rm_iter2);

        auto cm_iter = arr.template cbegin();
        auto cm_iter2 = cm_iter + 2;

        EXPECT_TRUE(cm_iter != cm_iter2);
        EXPECT_FALSE(cm_iter == cm_iter2);
        EXPECT_TRUE(cm_iter < cm_iter2);
        EXPECT_TRUE(cm_iter  cm_iter2);
        EXPECT_FALSE(cm_iter >= cm_iter2);
    }

    TEST(xiterator, assign)
    {
        row_major_result rm;
        using vector_type = row_major_result::vector_type;
        xarray_adaptor a(rm.storage(), rm.shape(), rm.strides());

        SUBCASE("row_major iterator")
        {
            xarray dst(a.shape(), 1);
            std::copy(
                a.cbegin(),
                a.cend(),
                dst.begin()
            );
            EXPECT_EQ(a, dst);
        }

        SUBCASE("column_major iterator")
        {
            xarray dst(a.shape(), 1);
            std::copy(
                a.cbegin(),
                a.cend(),
                dst.begin()
            );
            EXPECT_EQ(a, dst);
        }
    }

    TEST(xiterator, revert_assign)
    {
        row_major_result rm;
        using vector_type = row_major_result::vector_type;
        xarray_adaptor a(rm.storage(), rm.shape(), rm.strides());

        SUBCASE("row_major iterator")
        {
            xarray dst(a.shape(), 1);
            std::copy(
                a.crbegin(),
                a.crend(),
                dst.rbegin()
            );
            EXPECT_EQ(a, dst);
        }

        SUBCASE("column_major iterator")
        {
            xarray dst(a.shape(), 1);
            std::copy(
                a.crbegin(),
                a.crend(),
                dst.rbegin()
            );
            EXPECT_EQ(a, dst);
        }
    }

    TEST(xiterator, reverse_corner_cases)
    {
        xtensor a = {{{13, 16}, {13, 16}, {13, 16}}};

        constexpr auto cm = layout_type::column_major;
        constexpr auto rm = layout_type::row_major;
        {
            std::vector exp_iter = {16, 16, 16, 13, 13, 13};
            auto e_iter = exp_iter.begin();
            for (auto it = a.template rbegin(); it != a.template rend(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {16, 13, 16, 13, 16, 13};
            auto e_iter = exp_iter.begin();
            for (auto it = a.template rbegin(); it != a.template rend(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {13, 16, 13, 16, 13, 16};
            auto e_iter = exp_iter.begin();
            for (auto it = a.template begin(); it != a.template end(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {13, 13, 13, 16, 16, 16};
            auto e_iter = exp_iter.begin();
            for (auto it = a.template begin(); it != a.template end(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
        }

        xtensor b = {{{1}, {1}}, {{2}, {2}}, {{3}, {3}}};

        {
            std::vector exp_iter = {3, 2, 1, 3, 2, 1};
            auto e_iter = exp_iter.begin();
            for (auto it = b.template rbegin(); it != b.template rend(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {3, 3, 2, 2, 1, 1};
            auto e_iter = exp_iter.begin();
            for (auto it = b.template rbegin(); it != b.template rend(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {1, 1, 2, 2, 3, 3};
            auto e_iter = exp_iter.begin();
            for (auto it = b.template begin(); it != b.template end(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }

        {
            std::vector exp_iter = {1, 2, 3, 1, 2, 3};
            auto e_iter = exp_iter.begin();
            for (auto it = b.template begin(); it != b.template end(); ++it)
            {
                EXPECT_EQ(*e_iter, *it);
                ++e_iter;
            }
            EXPECT_TRUE(e_iter == exp_iter.end());
        }
    }
}

Web Proxy Viewer  |  New URL  |  Original Page