diff options
Diffstat (limited to 'src/boost/libs/numeric/ublas/test/tensor')
16 files changed, 4651 insertions, 0 deletions
diff --git a/src/boost/libs/numeric/ublas/test/tensor/Jamfile b/src/boost/libs/numeric/ublas/test/tensor/Jamfile new file mode 100644 index 00000000..0bbf2c56 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/Jamfile @@ -0,0 +1,42 @@ +# Boost.uBLAS +# +# Copyright (c) 2018 Cem Bassoy +# +# Use, modification and distribution is subject to the Boost Software License, +# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +project boost/ublas/test/tensor + : requirements + # these tests require C++17 + <cxxstd>11:<build>no + <toolset>gcc:<cxxflags>"-Wall -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-but-set-variable" + ; + +alias unit_test_framework + : # sources + /boost//unit_test_framework + ; + +# make aliases explicit so the libraries will only be built when requested +explicit unit_test_framework ; + + + +test-suite boost-ublas-tensor-test + : + [ run test_tensor.cpp + test_strides.cpp + test_operators_comparison.cpp + test_operators_arithmetic.cpp + test_multiplication.cpp + test_multi_index_utility.cpp + test_multi_index.cpp + test_functions.cpp + test_extents.cpp + test_expression_evaluation.cpp + test_einstein_notation.cpp + test_algorithms.cpp + test_tensor_matrix_vector.cpp + unit_test_framework ] + ; diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_algorithms.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_algorithms.cpp new file mode 100644 index 00000000..4215fc2a --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_algorithms.cpp @@ -0,0 +1,288 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + +#include <iostream> +#include <algorithm> +#include <vector> +#include <boost/numeric/ublas/tensor/algorithms.hpp> +#include <boost/numeric/ublas/tensor/extents.hpp> +#include <boost/numeric/ublas/tensor/strides.hpp> +#include "utility.hpp" + +#include <boost/test/unit_test.hpp> + + +BOOST_AUTO_TEST_SUITE ( test_tensor_algorithms, + * boost::unit_test::depends_on("test_extents") + * boost::unit_test::depends_on("test_strides")) + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; +using test_types2 = std::tuple<int,long,float,double,std::complex<float>>; + +struct fixture +{ + using extents_type = boost::numeric::ublas::shape; + fixture() + : extents { + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{4,1,3}, // 6 + extents_type{1,2,3}, // 7 + extents_type{4,2,3}, // 8 + extents_type{4,2,3,5} } // 9 + { + } + std::vector<extents_type> extents; +}; + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_copy, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector<value_type>; + + + for(auto const& n : extents) { + + auto a = vector_type(n.product()); + auto b = vector_type(n.product()); + auto c = vector_type(n.product()); + + auto wa = ublas::strides<ublas::first_order>(n); + auto wb = ublas::strides<ublas::last_order> (n); + auto wc = ublas::strides<ublas::first_order>(n); + + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=1){ + a[i]=v; + } + + ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ); + + for(auto i = 1ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i], a[i] ); + + using size_type = typename ublas::strides<ublas::first_order>::value_type; + size_type const*const p0 = nullptr; + BOOST_CHECK_THROW( ublas::copy( n.size(), p0, c.data(), wc.data(), b.data(), wb.data() ), std::length_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), p0, b.data(), wb.data() ), std::length_error ); + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), p0 ), std::length_error ); + + value_type* c0 = nullptr; + BOOST_CHECK_THROW( ublas::copy( n.size(), n.data(), c0, wc.data(), b.data(), wb.data() ), std::length_error ); + } + + // special case rank == 0 + { + auto n = ublas::shape{}; + + auto a = vector_type(n.product()); + auto b = vector_type(n.product()); + auto c = vector_type(n.product()); + + + auto wa = ublas::strides<ublas::first_order>(n); + auto wb = ublas::strides<ublas::last_order> (n); + auto wc = ublas::strides<ublas::first_order>(n); + + ublas::copy( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data() ); + ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ); + + + + BOOST_CHECK_NO_THROW( ublas::copy( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data() ) ); + + } + + + + + +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_transform, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector<value_type>; + + + for(auto const& n : extents) { + + auto a = vector_type(n.product()); + auto b = vector_type(n.product()); + auto c = vector_type(n.product()); + + auto wa = ublas::strides<ublas::first_order>(n); + auto wb = ublas::strides<ublas::last_order> (n); + auto wc = ublas::strides<ublas::first_order>(n); + + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=1){ + a[i]=v; + } + + ublas::transform( n.size(), n.data(), b.data(), wb.data(), a.data(), wa.data(), [](value_type const& a){ return a + value_type(1);} ); + ublas::transform( n.size(), n.data(), c.data(), wc.data(), b.data(), wb.data(), [](value_type const& a){ return a - value_type(1);} ); + + for(auto i = 1ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i], a[i] ); + + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_accumulate, value, test_types2, fixture ) +{ + using namespace boost::numeric; + using value_type = value; + using vector_type = std::vector<value_type>; + + + for(auto const& n : extents) { + + auto const s = n.product(); + + auto a = vector_type(n.product()); + // auto b = vector_type(n.product()); + // auto c = vector_type(n.product()); + + auto wa = ublas::strides<ublas::first_order>(n); + // auto wb = ublas::strides<ublas::last_order> (n); + // auto wc = ublas::strides<ublas::first_order>(n); + + auto v = value_type{}; + for(auto i = 0ul; i < a.size(); ++i, v+=value_type(1)){ + a[i]=v; + } + + auto acc = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v); + + BOOST_CHECK_EQUAL( acc, value_type( s*(s+1) / 2 ) ); + + + auto acc2 = ublas::accumulate( n.size(), n.data(), a.data(), wa.data(), v, + [](auto const& l, auto const& r){return l + r; }); + + BOOST_CHECK_EQUAL( acc2, value_type( s*(s+1) / 2 ) ); + + } +} + + + + +template<class V> +void init(std::vector<V>& a) +{ + auto v = V(1); + for(auto i = 0u; i < a.size(); ++i, ++v){ + a[i] = v; + } +} + +template<class V> +void init(std::vector<std::complex<V>>& a) +{ + auto v = std::complex<V>(1,1); + for(auto i = 0u; i < a.size(); ++i){ + a[i] = v; + v.real(v.real()+1); + v.imag(v.imag()+1); + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_algorithms_trans, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using vector_type = std::vector<value_type>; + using strides_type = ublas::strides<layout_type>; + using extents_type = ublas::shape; + using size_type = typename extents_type::value_type; + using permutation_type = std::vector<size_type>; + + + for(auto const& n : extents) { + + auto p = n.size(); + auto s = n.product(); + + auto pi = permutation_type(p); + auto a = vector_type(s); + auto b1 = vector_type(s); + auto b2 = vector_type(s); + auto c1 = vector_type(s); + auto c2 = vector_type(s); + + auto wa = strides_type(n); + + init(a); + + // so wie last-order. + for(auto i = size_type(0), j = p; i < n.size(); ++i, --j) + pi[i] = j; + + auto nc = typename extents_type::base_type (p); + for(auto i = 0u; i < p; ++i) + nc[pi[i]-1] = n[i]; + + auto wc = strides_type(extents_type(nc)); + auto wc_pi = typename strides_type::base_type (p); + for(auto i = 0u; i < p; ++i) + wc_pi[pi[i]-1] = wc[i]; + + ublas::copy ( p, n.data(), c1.data(), wc_pi.data(), a.data(), wa.data()); + ublas::trans( p, n.data(), pi.data(), c2.data(), wc.data(), a.data(), wa.data() ); + + if(!std::is_compound_v<value_type>) + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( c1[i], c2[i] ); + + + auto nb = typename extents_type::base_type (p); + for(auto i = 0u; i < p; ++i) + nb[pi[i]-1] = nc[i]; + + auto wb = strides_type (extents_type(nb)); + auto wb_pi = typename strides_type::base_type (p); + for(auto i = 0u; i < p; ++i) + wb_pi[pi[i]-1] = wb[i]; + + ublas::copy ( p, nc.data(), b1.data(), wb_pi.data(), c1.data(), wc.data()); + ublas::trans( p, nc.data(), pi.data(), b2.data(), wb.data(), c2.data(), wc.data() ); + + if(!std::is_compound_v<value_type>) + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( b1[i], b2[i] ); + + for(auto i = 0ul; i < s; ++i) + BOOST_CHECK_EQUAL( a[i], b2[i] ); + + } +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_einstein_notation.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_einstein_notation.cpp new file mode 100644 index 00000000..b0326c80 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_einstein_notation.cpp @@ -0,0 +1,122 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// +// And we acknowledge the support from all contributors. + + +#include <iostream> +#include <algorithm> +#include <boost/numeric/ublas/tensor.hpp> + +#include <boost/test/unit_test.hpp> + +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE ( test_einstein_notation, * boost::unit_test::depends_on("test_multi_index") ) + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +//using test_types = zip<int>::with_t<boost::numeric::ublas::first_order>; + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_einstein_multiplication, value, test_types ) +{ + using namespace boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = tensor<value_type,layout_type>; + using namespace boost::numeric::ublas::index; + + { + auto A = tensor_type{5,3}; + auto B = tensor_type{3,4}; + // auto C = tensor_type{4,5,6}; + + for(auto j = 0u; j < A.extents().at(1); ++j) + for(auto i = 0u; i < A.extents().at(0); ++i) + A.at( i,j ) = value_type(i+1); + + for(auto j = 0u; j < B.extents().at(1); ++j) + for(auto i = 0u; i < B.extents().at(0); ++i) + B.at( i,j ) = value_type(i+1); + + + + auto AB = A(_,_e) * B(_e,_); + + // std::cout << "A = " << A << std::endl; + // std::cout << "B = " << B << std::endl; + // std::cout << "AB = " << AB << std::endl; + + for(auto j = 0u; j < AB.extents().at(1); ++j) + for(auto i = 0u; i < AB.extents().at(0); ++i) + BOOST_CHECK_EQUAL( AB.at( i,j ) , value_type(A.at( i,0 ) * ( B.extents().at(0) * (B.extents().at(0)+1) / 2 )) ); + + + } + + + { + auto A = tensor_type{4,5,3}; + auto B = tensor_type{3,4,2}; + + for(auto k = 0u; k < A.extents().at(2); ++k) + for(auto j = 0u; j < A.extents().at(1); ++j) + for(auto i = 0u; i < A.extents().at(0); ++i) + A.at( i,j,k ) = value_type(i+1); + + for(auto k = 0u; k < B.extents().at(2); ++k) + for(auto j = 0u; j < B.extents().at(1); ++j) + for(auto i = 0u; i < B.extents().at(0); ++i) + B.at( i,j,k ) = value_type(i+1); + + auto AB = A(_d,_,_f) * B(_f,_d,_); + + // std::cout << "A = " << A << std::endl; + // std::cout << "B = " << B << std::endl; + // std::cout << "AB = " << AB << std::endl; + // n*(n+1)/2; + auto const nf = ( B.extents().at(0) * (B.extents().at(0)+1) / 2 ); + auto const nd = ( A.extents().at(0) * (A.extents().at(0)+1) / 2 ); + + for(auto j = 0u; j < AB.extents().at(1); ++j) + for(auto i = 0u; i < AB.extents().at(0); ++i) + BOOST_CHECK_EQUAL( AB.at( i,j ) , value_type(nf * nd) ); + + } + + + { + auto A = tensor_type{4,3}; + auto B = tensor_type{3,4,2}; + + for(auto j = 0u; j < A.extents().at(1); ++j) + for(auto i = 0u; i < A.extents().at(0); ++i) + A.at( i,j ) = value_type(i+1); + + for(auto k = 0u; k < B.extents().at(2); ++k) + for(auto j = 0u; j < B.extents().at(1); ++j) + for(auto i = 0u; i < B.extents().at(0); ++i) + B.at( i,j,k ) = value_type(i+1); + + auto AB = A(_d,_f) * B(_f,_d,_); + + // n*(n+1)/2; + auto const nf = ( B.extents().at(0) * (B.extents().at(0)+1) / 2 ); + auto const nd = ( A.extents().at(0) * (A.extents().at(0)+1) / 2 ); + + for(auto i = 0u; i < AB.extents().at(0); ++i) + BOOST_CHECK_EQUAL ( AB.at( i ) , value_type(nf * nd) ); + + } +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_expression.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_expression.cpp new file mode 100644 index 00000000..ae3ce205 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_expression.cpp @@ -0,0 +1,170 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + + +#include <boost/numeric/ublas/tensor/expression.hpp> +#include <boost/numeric/ublas/tensor/tensor.hpp> +#include <boost/test/unit_test.hpp> +#include "utility.hpp" + +#include <functional> +#include <complex> + + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + + +struct fixture +{ + using extents_type = boost::numeric::ublas::shape; + fixture() + : extents { + extents_type{}, // 0 + + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{1,2,3}, // 6 + extents_type{1,1,2,3}, // 7 + extents_type{1,2,3,1,1}, // 8 + + extents_type{4,2,3}, // 9 + extents_type{4,2,1,3}, // 10 + extents_type{4,2,1,3,1}, // 11 + extents_type{1,4,2,1,3,1} } // 12 + { + } + std::vector<extents_type> extents; +}; + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_access, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using tensor_expression_type = typename tensor_type::super_type; + + + for(auto const& e : extents) { + + auto v = value_type{}; + auto t = tensor_type(e); + + for(auto& tt: t){ tt = v; v+=value_type{1}; } + const auto& tensor_expression_const = static_cast<tensor_expression_type const&>( t ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( tensor_expression_const()(i), t(i) ); + + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_expression, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto uplus1 = std::bind( std::plus<value_type>{}, std::placeholders::_1, value_type(1) ); + + for(auto const& e : extents) { + + auto t = tensor_type(e); + auto v = value_type{}; + for(auto& tt: t) { tt = v; v+=value_type{1}; } + + const auto uexpr = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus1 ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( uexpr(i), uplus1(t(i)) ); + + auto uexpr_uexpr = ublas::detail::make_unary_tensor_expression<tensor_type>( uexpr, uplus1 ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( uexpr_uexpr(i), uplus1(uplus1(t(i))) ); + + const auto & uexpr_e = uexpr.e; + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_e) >, tensor_type > ) ); + + const auto & uexpr_uexpr_e_e = uexpr_uexpr.e.e; + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr_uexpr_e_e) >, tensor_type > ) ); + + + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_expression, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto uplus1 = std::bind( std::plus<value_type>{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus<value_type>{}, std::placeholders::_1, value_type(2) ); + auto bplus = std::plus <value_type>{}; + auto bminus = std::minus<value_type>{}; + + for(auto const& e : extents) { + + auto t = tensor_type(e); + auto v = value_type{}; + for(auto& tt: t){ tt = v; v+=value_type{1}; } + + auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus2 ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr1.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(uexpr2.e) >, tensor_type > ) ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( uexpr1(i), uplus1(t(i)) ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( uexpr2(i), uplus2(t(i)) ); + + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.el.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_uexpr.er.e) >, tensor_type > ) ); + + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( bexpr_uexpr(i), bplus(uexpr1(i),uexpr2(i)) ); + + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.el.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.el.er.e) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_type > ) ); + BOOST_CHECK( ( std::is_same_v< std::decay_t< decltype(bexpr_bexpr_uexpr.er) >, tensor_type > ) ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( bexpr_bexpr_uexpr(i), bminus(bexpr_uexpr(i),t(i)) ); + + } + + +} diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_expression_evaluation.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_expression_evaluation.cpp new file mode 100644 index 00000000..002d51a2 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_expression_evaluation.cpp @@ -0,0 +1,240 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + +#include <boost/numeric/ublas/tensor/expression_evaluation.hpp> +#include <boost/numeric/ublas/tensor/expression.hpp> +#include <boost/numeric/ublas/tensor/tensor.hpp> +#include <boost/test/unit_test.hpp> +#include "utility.hpp" + +#include <functional> + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + + +struct fixture +{ + using extents_type = boost::numeric::ublas::shape; + fixture() + : extents{ + extents_type{}, // 0 + + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{1,2,3}, // 6 + extents_type{1,1,2,3}, // 7 + extents_type{1,2,3,1,1}, // 8 + + extents_type{4,2,3}, // 9 + extents_type{4,2,1,3}, // 10 + extents_type{4,2,1,3,1}, // 11 + extents_type{1,4,2,1,3,1}} // 12 + { + } + std::vector<extents_type> extents; +}; + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_retrieve_extents, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto uplus1 = std::bind( std::plus<value_type>{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus<value_type>{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus <value_type>{}; + auto bminus = std::minus<value_type>{}; + + for(auto const& e : extents) { + + auto t = tensor_type(e); + auto v = value_type{}; + for(auto& tt: t){ tt = v; v+=value_type{1}; } + + + BOOST_CHECK( ublas::detail::retrieve_extents( t ) == e ); + + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus2 ); + + BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) == e ); + BOOST_CHECK( ublas::detail::retrieve_extents( uexpr2 ) == e ); + + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == e ); + + + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr ) == e ); + + } + + + for(auto i = 0u; i < extents.size()-1; ++i) + { + + auto v = value_type{}; + + auto t1 = tensor_type(extents[i]); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + auto t2 = tensor_type(extents[i+1]); + for(auto& tt: t2){ tt = v; v+=value_type{2}; } + + BOOST_CHECK( ublas::detail::retrieve_extents( t1 ) != ublas::detail::retrieve_extents( t2 ) ); + + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_type>( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_type>( t2, uplus2 ); + + BOOST_CHECK( ublas::detail::retrieve_extents( t1 ) == ublas::detail::retrieve_extents( uexpr1 ) ); + BOOST_CHECK( ublas::detail::retrieve_extents( t2 ) == ublas::detail::retrieve_extents( uexpr2 ) ); + BOOST_CHECK( ublas::detail::retrieve_extents( uexpr1 ) != ublas::detail::retrieve_extents( uexpr2 ) ); + + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_uexpr ) == ublas::detail::retrieve_extents(t1) ); + + + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr, t2, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) == ublas::detail::retrieve_extents(t2) ); + + + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression<tensor_type>( t2, bexpr_uexpr, bminus ); + + BOOST_CHECK( ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) == ublas::detail::retrieve_extents(t2) ); + } +} + + + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_expression_all_extents_equal, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto uplus1 = std::bind( std::plus<value_type>{}, std::placeholders::_1, value_type(1) ); + auto uplus2 = std::bind( std::plus<value_type>{}, value_type(2), std::placeholders::_2 ); + auto bplus = std::plus <value_type>{}; + auto bminus = std::minus<value_type>{}; + + for(auto const& e : extents) { + + auto t = tensor_type(e); + auto v = value_type{}; + for(auto& tt: t){ tt = v; v+=value_type{1}; } + + + BOOST_CHECK( ublas::detail::all_extents_equal( t , e ) ); + + + // uexpr1 = t+1 + // uexpr2 = 2+t + auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_type>( t, uplus2 ); + + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, e ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, e ) ); + + // bexpr_uexpr = (t+1) + (2+t) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_uexpr, e ) ); + + + // bexpr_bexpr_uexpr = ((t+1) + (2+t)) - t + auto bexpr_bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr, t, bminus ); + + BOOST_CHECK( ublas::detail::all_extents_equal( bexpr_bexpr_uexpr , e ) ); + + } + + + for(auto i = 0u; i < extents.size()-1; ++i) + { + + auto v = value_type{}; + + auto t1 = tensor_type(extents[i]); + for(auto& tt: t1){ tt = v; v+=value_type{1}; } + + auto t2 = tensor_type(extents[i+1]); + for(auto& tt: t2){ tt = v; v+=value_type{2}; } + + BOOST_CHECK( ublas::detail::all_extents_equal( t1, ublas::detail::retrieve_extents(t1) ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( t2, ublas::detail::retrieve_extents(t2) ) ); + + // uexpr1 = t1+1 + // uexpr2 = 2+t2 + auto uexpr1 = ublas::detail::make_unary_tensor_expression<tensor_type>( t1, uplus1 ); + auto uexpr2 = ublas::detail::make_unary_tensor_expression<tensor_type>( t2, uplus2 ); + + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr1, ublas::detail::retrieve_extents(uexpr1) ) ); + BOOST_CHECK( ublas::detail::all_extents_equal( uexpr2, ublas::detail::retrieve_extents(uexpr2) ) ); + + // bexpr_uexpr = (t1+1) + (2+t2) + auto bexpr_uexpr = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, uexpr2, bplus ); + + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr, ublas::detail::retrieve_extents( bexpr_uexpr ) ) ); + + // bexpr_bexpr_uexpr = ((t1+1) + (2+t2)) - t2 + auto bexpr_bexpr_uexpr1 = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr, t2, bminus ); + + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr1, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr1 ) ) ); + + // bexpr_bexpr_uexpr = t2 - ((t1+1) + (2+t2)) + auto bexpr_bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression<tensor_type>( t2, bexpr_uexpr, bminus ); + + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr2 ) ) ); + + + // bexpr_uexpr2 = (t1+1) + t2 + auto bexpr_uexpr2 = ublas::detail::make_binary_tensor_expression<tensor_type>( uexpr1, t2, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_uexpr2, ublas::detail::retrieve_extents( bexpr_uexpr2 ) ) ); + + + // bexpr_uexpr2 = ((t1+1) + t2) + t1 + auto bexpr_bexpr_uexpr3 = ublas::detail::make_binary_tensor_expression<tensor_type>( bexpr_uexpr2, t1, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr3, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr3 ) ) ); + + // bexpr_uexpr2 = t1 + (((t1+1) + t2) + t1) + auto bexpr_bexpr_uexpr4 = ublas::detail::make_binary_tensor_expression<tensor_type>( t1, bexpr_bexpr_uexpr3, bplus ); + BOOST_CHECK( ! ublas::detail::all_extents_equal( bexpr_bexpr_uexpr4, ublas::detail::retrieve_extents( bexpr_bexpr_uexpr4 ) ) ); + + } +} diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_extents.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_extents.cpp new file mode 100644 index 00000000..9fbeee94 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_extents.cpp @@ -0,0 +1,449 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include <boost/test/unit_test.hpp> +#include <boost/numeric/ublas/tensor/extents.hpp> +#include <vector> + +BOOST_AUTO_TEST_SUITE ( test_extents ) + + +//*boost::unit_test::label("extents") +//*boost::unit_test::label("constructor") + +BOOST_AUTO_TEST_CASE(test_extents_ctor) +{ + using namespace boost::numeric; + using extents = ublas::basic_extents<unsigned>; + + + auto e0 = extents{}; + BOOST_CHECK( e0.empty()); + BOOST_CHECK_EQUAL ( e0.size(),0); + + auto e1 = extents{1,1}; + BOOST_CHECK(!e1.empty()); + BOOST_CHECK_EQUAL ( e1.size(),2); + + auto e2 = extents{1,2}; + BOOST_CHECK(!e2.empty()); + BOOST_CHECK_EQUAL ( e2.size(),2); + + auto e3 = extents{2,1}; + BOOST_CHECK (!e3.empty()); + BOOST_CHECK_EQUAL ( e3.size(),2); + + auto e4 = extents{2,3}; + BOOST_CHECK(!e4.empty()); + BOOST_CHECK_EQUAL ( e4.size(),2); + + auto e5 = extents{2,3,1}; + BOOST_CHECK (!e5.empty()); + BOOST_CHECK_EQUAL ( e5.size(),3); + + auto e6 = extents{1,2,3}; // 6 + BOOST_CHECK(!e6.empty()); + BOOST_CHECK_EQUAL ( e6.size(),3); + + auto e7 = extents{4,2,3}; // 7 + BOOST_CHECK(!e7.empty()); + BOOST_CHECK_EQUAL ( e7.size(),3); + + BOOST_CHECK_THROW( extents({1,0}), std::length_error ); + BOOST_CHECK_THROW( extents({0} ), std::length_error ); + BOOST_CHECK_THROW( extents({3} ), std::length_error ); + BOOST_CHECK_THROW( extents({0,1}), std::length_error ); +} + + + + +struct fixture { + using extents_type = boost::numeric::ublas::basic_extents<unsigned>; + fixture() : extents{ + extents_type{}, // 0 + + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{1,2,3}, // 6 + extents_type{1,1,2,3}, // 7 + extents_type{1,2,3,1,1}, // 8 + + extents_type{4,2,3}, // 9 + extents_type{4,2,1,3}, // 10 + extents_type{4,2,1,3,1}, // 11 + extents_type{1,4,2,1,3,1}, // 12 +} // 13 + {} + std::vector<extents_type> extents; +}; + +BOOST_FIXTURE_TEST_CASE(test_extents_access, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("access")) +{ + using namespace boost::numeric; + + BOOST_REQUIRE_EQUAL(extents.size(),13); + + BOOST_CHECK_EQUAL (extents[ 0].size(), 0); + BOOST_CHECK (extents[ 0].empty() ); + + BOOST_REQUIRE_EQUAL(extents[ 1].size(), 2); + BOOST_REQUIRE_EQUAL(extents[ 2].size(), 2); + BOOST_REQUIRE_EQUAL(extents[ 3].size(), 2); + BOOST_REQUIRE_EQUAL(extents[ 4].size(), 2); + BOOST_REQUIRE_EQUAL(extents[ 5].size(), 3); + BOOST_REQUIRE_EQUAL(extents[ 6].size(), 3); + BOOST_REQUIRE_EQUAL(extents[ 7].size(), 4); + BOOST_REQUIRE_EQUAL(extents[ 8].size(), 5); + BOOST_REQUIRE_EQUAL(extents[ 9].size(), 3); + BOOST_REQUIRE_EQUAL(extents[10].size(), 4); + BOOST_REQUIRE_EQUAL(extents[11].size(), 5); + BOOST_REQUIRE_EQUAL(extents[12].size(), 6); + + + BOOST_CHECK_EQUAL(extents[1][0],1); + BOOST_CHECK_EQUAL(extents[1][1],1); + + BOOST_CHECK_EQUAL(extents[2][0],1); + BOOST_CHECK_EQUAL(extents[2][1],2); + + BOOST_CHECK_EQUAL(extents[3][0],2); + BOOST_CHECK_EQUAL(extents[3][1],1); + + BOOST_CHECK_EQUAL(extents[4][0],2); + BOOST_CHECK_EQUAL(extents[4][1],3); + + BOOST_CHECK_EQUAL(extents[5][0],2); + BOOST_CHECK_EQUAL(extents[5][1],3); + BOOST_CHECK_EQUAL(extents[5][2],1); + + BOOST_CHECK_EQUAL(extents[6][0],1); + BOOST_CHECK_EQUAL(extents[6][1],2); + BOOST_CHECK_EQUAL(extents[6][2],3); + + BOOST_CHECK_EQUAL(extents[7][0],1); + BOOST_CHECK_EQUAL(extents[7][1],1); + BOOST_CHECK_EQUAL(extents[7][2],2); + BOOST_CHECK_EQUAL(extents[7][3],3); + + BOOST_CHECK_EQUAL(extents[8][0],1); + BOOST_CHECK_EQUAL(extents[8][1],2); + BOOST_CHECK_EQUAL(extents[8][2],3); + BOOST_CHECK_EQUAL(extents[8][3],1); + BOOST_CHECK_EQUAL(extents[8][4],1); + + BOOST_CHECK_EQUAL(extents[9][0],4); + BOOST_CHECK_EQUAL(extents[9][1],2); + BOOST_CHECK_EQUAL(extents[9][2],3); + + BOOST_CHECK_EQUAL(extents[10][0],4); + BOOST_CHECK_EQUAL(extents[10][1],2); + BOOST_CHECK_EQUAL(extents[10][2],1); + BOOST_CHECK_EQUAL(extents[10][3],3); + + BOOST_CHECK_EQUAL(extents[11][0],4); + BOOST_CHECK_EQUAL(extents[11][1],2); + BOOST_CHECK_EQUAL(extents[11][2],1); + BOOST_CHECK_EQUAL(extents[11][3],3); + BOOST_CHECK_EQUAL(extents[11][4],1); + + BOOST_CHECK_EQUAL(extents[12][0],1); + BOOST_CHECK_EQUAL(extents[12][1],4); + BOOST_CHECK_EQUAL(extents[12][2],2); + BOOST_CHECK_EQUAL(extents[12][3],1); + BOOST_CHECK_EQUAL(extents[12][4],3); + BOOST_CHECK_EQUAL(extents[12][5],1); +} + +BOOST_FIXTURE_TEST_CASE(test_extents_copy_ctor, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("copy_ctor")) +{ + BOOST_REQUIRE_EQUAL(extents.size(),13); + + auto e0 = extents[ 0]; // {} + auto e1 = extents[ 1]; // {1,1} + auto e2 = extents[ 2]; // {1,2} + auto e3 = extents[ 3]; // {2,1} + auto e4 = extents[ 4]; // {2,3} + auto e5 = extents[ 5]; // {2,3,1} + auto e6 = extents[ 6]; // {1,2,3} + auto e7 = extents[ 7]; // {1,1,2,3} + auto e8 = extents[ 8]; // {1,2,3,1,1} + auto e9 = extents[ 9]; // {4,2,3} + auto e10 = extents[10]; // {4,2,1,3} + auto e11 = extents[11]; // {4,2,1,3,1} + auto e12 = extents[12]; // {1,4,2,1,3,1} + + BOOST_CHECK_EQUAL (e0.size(), 0); + BOOST_CHECK (e0.empty() ); + + BOOST_REQUIRE_EQUAL(e1 .size(), 2); + BOOST_REQUIRE_EQUAL(e2 .size(), 2); + BOOST_REQUIRE_EQUAL(e3 .size(), 2); + BOOST_REQUIRE_EQUAL(e4 .size(), 2); + BOOST_REQUIRE_EQUAL(e5 .size(), 3); + BOOST_REQUIRE_EQUAL(e6 .size(), 3); + BOOST_REQUIRE_EQUAL(e7 .size(), 4); + BOOST_REQUIRE_EQUAL(e8 .size(), 5); + BOOST_REQUIRE_EQUAL(e9 .size(), 3); + BOOST_REQUIRE_EQUAL(e10.size(), 4); + BOOST_REQUIRE_EQUAL(e11.size(), 5); + BOOST_REQUIRE_EQUAL(e12.size(), 6); + + + BOOST_CHECK_EQUAL(e1[0],1); + BOOST_CHECK_EQUAL(e1[1],1); + + BOOST_CHECK_EQUAL(e2[0],1); + BOOST_CHECK_EQUAL(e2[1],2); + + BOOST_CHECK_EQUAL(e3[0],2); + BOOST_CHECK_EQUAL(e3[1],1); + + BOOST_CHECK_EQUAL(e4[0],2); + BOOST_CHECK_EQUAL(e4[1],3); + + BOOST_CHECK_EQUAL(e5[0],2); + BOOST_CHECK_EQUAL(e5[1],3); + BOOST_CHECK_EQUAL(e5[2],1); + + BOOST_CHECK_EQUAL(e6[0],1); + BOOST_CHECK_EQUAL(e6[1],2); + BOOST_CHECK_EQUAL(e6[2],3); + + BOOST_CHECK_EQUAL(e7[0],1); + BOOST_CHECK_EQUAL(e7[1],1); + BOOST_CHECK_EQUAL(e7[2],2); + BOOST_CHECK_EQUAL(e7[3],3); + + BOOST_CHECK_EQUAL(e8[0],1); + BOOST_CHECK_EQUAL(e8[1],2); + BOOST_CHECK_EQUAL(e8[2],3); + BOOST_CHECK_EQUAL(e8[3],1); + BOOST_CHECK_EQUAL(e8[4],1); + + BOOST_CHECK_EQUAL(e9[0],4); + BOOST_CHECK_EQUAL(e9[1],2); + BOOST_CHECK_EQUAL(e9[2],3); + + BOOST_CHECK_EQUAL(e10[0],4); + BOOST_CHECK_EQUAL(e10[1],2); + BOOST_CHECK_EQUAL(e10[2],1); + BOOST_CHECK_EQUAL(e10[3],3); + + BOOST_CHECK_EQUAL(e11[0],4); + BOOST_CHECK_EQUAL(e11[1],2); + BOOST_CHECK_EQUAL(e11[2],1); + BOOST_CHECK_EQUAL(e11[3],3); + BOOST_CHECK_EQUAL(e11[4],1); + + BOOST_CHECK_EQUAL(e12[0],1); + BOOST_CHECK_EQUAL(e12[1],4); + BOOST_CHECK_EQUAL(e12[2],2); + BOOST_CHECK_EQUAL(e12[3],1); + BOOST_CHECK_EQUAL(e12[4],3); + BOOST_CHECK_EQUAL(e12[5],1); + +} + +BOOST_FIXTURE_TEST_CASE(test_extents_is, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("query")) +{ + BOOST_REQUIRE_EQUAL(extents.size(),13); + + auto e0 = extents[ 0]; // {} + auto e1 = extents[ 1]; // {1,1} + auto e2 = extents[ 2]; // {1,2} + auto e3 = extents[ 3]; // {2,1} + auto e4 = extents[ 4]; // {2,3} + auto e5 = extents[ 5]; // {2,3,1} + auto e6 = extents[ 6]; // {1,2,3} + auto e7 = extents[ 7]; // {1,1,2,3} + auto e8 = extents[ 8]; // {1,2,3,1,1} + auto e9 = extents[ 9]; // {4,2,3} + auto e10 = extents[10]; // {4,2,1,3} + auto e11 = extents[11]; // {4,2,1,3,1} + auto e12 = extents[12]; // {1,4,2,1,3,1} + + BOOST_CHECK( e0.empty ()); + BOOST_CHECK( ! e0.is_scalar()); + BOOST_CHECK( ! e0.is_vector()); + BOOST_CHECK( ! e0.is_matrix()); + BOOST_CHECK( ! e0.is_tensor()); + + BOOST_CHECK( ! e1.empty () ); + BOOST_CHECK( e1.is_scalar() ); + BOOST_CHECK( ! e1.is_vector() ); + BOOST_CHECK( ! e1.is_matrix() ); + BOOST_CHECK( ! e1.is_tensor() ); + + BOOST_CHECK( ! e2.empty () ); + BOOST_CHECK( ! e2.is_scalar() ); + BOOST_CHECK( e2.is_vector() ); + BOOST_CHECK( ! e2.is_matrix() ); + BOOST_CHECK( ! e2.is_tensor() ); + + BOOST_CHECK( ! e3.empty () ); + BOOST_CHECK( ! e3.is_scalar() ); + BOOST_CHECK( e3.is_vector() ); + BOOST_CHECK( ! e3.is_matrix() ); + BOOST_CHECK( ! e3.is_tensor() ); + + BOOST_CHECK( ! e4.empty () ); + BOOST_CHECK( ! e4.is_scalar() ); + BOOST_CHECK( ! e4.is_vector() ); + BOOST_CHECK( e4.is_matrix() ); + BOOST_CHECK( ! e4.is_tensor() ); + + BOOST_CHECK( ! e5.empty () ); + BOOST_CHECK( ! e5.is_scalar() ); + BOOST_CHECK( ! e5.is_vector() ); + BOOST_CHECK( e5.is_matrix() ); + BOOST_CHECK( ! e5.is_tensor() ); + + BOOST_CHECK( ! e6.empty () ); + BOOST_CHECK( ! e6.is_scalar() ); + BOOST_CHECK( ! e6.is_vector() ); + BOOST_CHECK( ! e6.is_matrix() ); + BOOST_CHECK( e6.is_tensor() ); + + BOOST_CHECK( ! e7.empty () ); + BOOST_CHECK( ! e7.is_scalar() ); + BOOST_CHECK( ! e7.is_vector() ); + BOOST_CHECK( ! e7.is_matrix() ); + BOOST_CHECK( e7.is_tensor() ); + + BOOST_CHECK( ! e8.empty () ); + BOOST_CHECK( ! e8.is_scalar() ); + BOOST_CHECK( ! e8.is_vector() ); + BOOST_CHECK( ! e8.is_matrix() ); + BOOST_CHECK( e8.is_tensor() ); + + BOOST_CHECK( ! e9.empty () ); + BOOST_CHECK( ! e9.is_scalar() ); + BOOST_CHECK( ! e9.is_vector() ); + BOOST_CHECK( ! e9.is_matrix() ); + BOOST_CHECK( e9.is_tensor() ); + + BOOST_CHECK( ! e10.empty () ); + BOOST_CHECK( ! e10.is_scalar() ); + BOOST_CHECK( ! e10.is_vector() ); + BOOST_CHECK( ! e10.is_matrix() ); + BOOST_CHECK( e10.is_tensor() ); + + BOOST_CHECK( ! e11.empty () ); + BOOST_CHECK( ! e11.is_scalar() ); + BOOST_CHECK( ! e11.is_vector() ); + BOOST_CHECK( ! e11.is_matrix() ); + BOOST_CHECK( e11.is_tensor() ); + + BOOST_CHECK( ! e12.empty () ); + BOOST_CHECK( ! e12.is_scalar() ); + BOOST_CHECK( ! e12.is_vector() ); + BOOST_CHECK( ! e12.is_matrix() ); + BOOST_CHECK( e12.is_tensor() ); +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_squeeze, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("squeeze")) +{ + BOOST_REQUIRE_EQUAL(extents.size(),13); + + auto e0 = extents[ 0].squeeze(); // {} + auto e1 = extents[ 1].squeeze(); // {1,1} + auto e2 = extents[ 2].squeeze(); // {1,2} + auto e3 = extents[ 3].squeeze(); // {2,1} + + auto e4 = extents[ 4].squeeze(); // {2,3} + auto e5 = extents[ 5].squeeze(); // {2,3} + auto e6 = extents[ 6].squeeze(); // {2,3} + auto e7 = extents[ 7].squeeze(); // {2,3} + auto e8 = extents[ 8].squeeze(); // {2,3} + + auto e9 = extents[ 9].squeeze(); // {4,2,3} + auto e10 = extents[10].squeeze(); // {4,2,3} + auto e11 = extents[11].squeeze(); // {4,2,3} + auto e12 = extents[12].squeeze(); // {4,2,3} + + BOOST_CHECK( (e0 == extents_type{} ) ); + BOOST_CHECK( (e1 == extents_type{1,1}) ); + BOOST_CHECK( (e2 == extents_type{1,2}) ); + BOOST_CHECK( (e3 == extents_type{2,1}) ); + + BOOST_CHECK( (e4 == extents_type{2,3}) ); + BOOST_CHECK( (e5 == extents_type{2,3}) ); + BOOST_CHECK( (e6 == extents_type{2,3}) ); + BOOST_CHECK( (e7 == extents_type{2,3}) ); + BOOST_CHECK( (e8 == extents_type{2,3}) ); + + BOOST_CHECK( (e9 == extents_type{4,2,3}) ); + BOOST_CHECK( (e10 == extents_type{4,2,3}) ); + BOOST_CHECK( (e11 == extents_type{4,2,3}) ); + BOOST_CHECK( (e12 == extents_type{4,2,3}) ); + +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_valid, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("valid")) +{ + + using namespace boost::numeric; + + BOOST_REQUIRE_EQUAL(extents.size(),13); + + for(auto const& e : extents){ + if(e.empty()) + BOOST_CHECK_EQUAL(e.valid(),false); + else + BOOST_CHECK_EQUAL(e.valid(), true ); + } + + BOOST_CHECK_EQUAL( extents_type{}.valid() , false ); + + BOOST_CHECK_THROW( ublas::basic_extents<unsigned>({0,1}), std::length_error ); + BOOST_CHECK_THROW( ublas::basic_extents<unsigned>({1,0,1}), std::length_error ); + +} + + +BOOST_FIXTURE_TEST_CASE(test_extents_product, fixture, *boost::unit_test::label("extents") *boost::unit_test::label("product")) +{ + + auto e0 = extents[ 0].product(); // {} + auto e1 = extents[ 1].product(); // {1,1} + auto e2 = extents[ 2].product(); // {1,2} + auto e3 = extents[ 3].product(); // {2,1} + auto e4 = extents[ 4].product(); // {2,3} + auto e5 = extents[ 5].product(); // {2,3,1} + auto e6 = extents[ 6].product(); // {1,2,3} + auto e7 = extents[ 7].product(); // {1,1,2,3} + auto e8 = extents[ 8].product(); // {1,2,3,1,1} + auto e9 = extents[ 9].product(); // {4,2,3} + auto e10 = extents[10].product(); // {4,2,1,3} + auto e11 = extents[11].product(); // {4,2,1,3,1} + auto e12 = extents[12].product(); // {1,4,2,1,3,1} + + BOOST_CHECK_EQUAL( e0 , 0 ); + BOOST_CHECK_EQUAL( e1 , 1 ); + BOOST_CHECK_EQUAL( e2 , 2 ); + BOOST_CHECK_EQUAL( e3 , 2 ); + BOOST_CHECK_EQUAL( e4 , 6 ); + BOOST_CHECK_EQUAL( e5 , 6 ); + BOOST_CHECK_EQUAL( e6 , 6 ); + BOOST_CHECK_EQUAL( e7 , 6 ); + BOOST_CHECK_EQUAL( e8 , 6 ); + BOOST_CHECK_EQUAL( e9 , 24 ); + BOOST_CHECK_EQUAL( e10, 24 ); + BOOST_CHECK_EQUAL( e11, 24 ); + BOOST_CHECK_EQUAL( e12, 24 ); + + +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_functions.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_functions.cpp new file mode 100644 index 00000000..64ecda39 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_functions.cpp @@ -0,0 +1,453 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// +// And we acknowledge the support from all contributors. + + +#include <iostream> +#include <algorithm> +#include <boost/numeric/ublas/tensor.hpp> +#include <boost/numeric/ublas/matrix.hpp> +#include <boost/numeric/ublas/vector.hpp> + +#include <boost/test/unit_test.hpp> + +#include "utility.hpp" + +BOOST_AUTO_TEST_SUITE ( test_tensor_functions, * boost::unit_test::depends_on("test_tensor_contraction") ) + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +//using test_types = zip<int>::with_t<boost::numeric::ublas::first_order>; + + +struct fixture +{ + using extents_type = boost::numeric::ublas::shape; + fixture() + : extents { + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{4,1,3}, // 6 + extents_type{1,2,3}, // 7 + extents_type{4,2,3}, // 8 + extents_type{4,2,3,5}} // 9 + { + } + std::vector<extents_type> extents; +}; + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_vector, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + using vector_type = typename tensor_type::vector_type; + + + for(auto const& n : extents){ + + auto a = tensor_type(n, value_type{2}); + + for(auto m = 0u; m < n.size(); ++m){ + + auto b = vector_type (n[m], value_type{1} ); + + auto c = ublas::prod(a, b, m+1); + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type(n[m]) * a[i] ); + + } + } +} + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_matrix, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + + for(auto const& n : extents) { + + auto a = tensor_type(n, value_type{2}); + + for(auto m = 0u; m < n.size(); ++m){ + + auto b = matrix_type ( n[m], n[m], value_type{1} ); + + auto c = ublas::prod(a, b, m+1); + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type(n[m]) * a[i] ); + + } + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_1, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + // left-hand and right-hand side have the + // the same number of elements + + for(auto const& na : extents) { + + auto a = tensor_type( na, value_type{2} ); + auto b = tensor_type( na, value_type{3} ); + + auto const pa = a.rank(); + + // the number of contractions is changed. + for( auto q = 0ul; q <= pa; ++q) { // pa + + auto phi = std::vector<std::size_t> ( q ); + + std::iota(phi.begin(), phi.end(), 1ul); + + auto c = ublas::prod(a, b, phi); + + auto acc = value_type(1); + for(auto i = 0ul; i < q; ++i) + acc *= a.extents().at(phi.at(i)-1); + + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + } + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_prod_tensor_2, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto permute_extents = [](auto const& pi, auto const& na){ + auto nb = na; + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[pi[j]-1] = na[j]; + return nb; + }; + + + // left-hand and right-hand side have the + // the same number of elements + + for(auto const& na : extents) { + + auto a = tensor_type( na, value_type{2} ); + auto const pa = a.rank(); + + + auto pi = std::vector<std::size_t>(pa); + auto fac = compute_factorial(pa); + std::iota( pi.begin(), pi.end(), 1 ); + + for(auto f = 0ul; f < fac; ++f) + { + auto nb = permute_extents( pi, na ); + auto b = tensor_type( nb, value_type{3} ); + + // the number of contractions is changed. + for( auto q = 0ul; q <= pa; ++q) { // pa + + auto phia = std::vector<std::size_t> ( q ); // concatenation for a + auto phib = std::vector<std::size_t> ( q ); // concatenation for b + + std::iota(phia.begin(), phia.end(), 1ul); + std::transform( phia.begin(), phia.end(), phib.begin(), + [&pi] ( std::size_t i ) { return pi.at(i-1); } ); + + auto c = ublas::prod(a, b, phia, phib); + + auto acc = value_type(1); + for(auto i = 0ul; i < q; ++i) + acc *= a.extents().at(phia.at(i)-1); + + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + } + + std::next_permutation(pi.begin(), pi.end()); + } + } +} + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner_prod, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + + for(auto const& n : extents) { + + auto a = tensor_type(n, value_type(2)); + auto b = tensor_type(n, value_type(1)); + + auto c = ublas::inner_prod(a, b); + auto r = std::inner_product(a.begin(),a.end(), b.begin(),value_type(0)); + + BOOST_CHECK_EQUAL( c , r ); + + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_norm, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + + for(auto const& n : extents) { + + auto a = tensor_type(n); + + auto one = value_type(1); + auto v = one; + for(auto& aa: a) + aa = v, v += one; + + + auto c = ublas::inner_prod(a, a); + auto r = std::inner_product(a.begin(),a.end(), a.begin(),value_type(0)); + + auto r2 = ublas::norm( (a+a) / 2 ); + + BOOST_CHECK_EQUAL( c , r ); + BOOST_CHECK_EQUAL( std::sqrt( c ) , r2 ); + + } +} + + +BOOST_FIXTURE_TEST_CASE( test_tensor_real_imag_conj, fixture ) +{ + using namespace boost::numeric; + using value_type = float; + using complex_type = std::complex<value_type>; + using layout_type = ublas::first_order; + + using tensor_complex_type = ublas::tensor<complex_type,layout_type>; + using tensor_type = ublas::tensor<value_type,layout_type>; + + for(auto const& n : extents) { + + auto a = tensor_type(n); + auto r0 = tensor_type(n); + auto r00 = tensor_complex_type(n); + + + auto one = value_type(1); + auto v = one; + for(auto& aa: a) + aa = v, v += one; + + tensor_type b = (a+a) / value_type( 2 ); + tensor_type r1 = ublas::real( (a+a) / value_type( 2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::real( l ); } ); + BOOST_CHECK( r0 == r1 ); + + tensor_type r2 = ublas::imag( (a+a) / value_type( 2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::imag( l ); } ); + BOOST_CHECK( r0 == r2 ); + + tensor_complex_type r3 = ublas::conj( (a+a) / value_type( 2 ) ); + std::transform( b.begin(), b.end(), r00.begin(), [](auto const& l){ return std::conj( l ); } ); + BOOST_CHECK( r00 == r3 ); + + } + + for(auto const& n : extents) { + + + + + auto a = tensor_complex_type(n); + + auto r00 = tensor_complex_type(n); + auto r0 = tensor_type(n); + + + auto one = complex_type(1,1); + auto v = one; + for(auto& aa: a) + aa = v, v = v + one; + + tensor_complex_type b = (a+a) / complex_type( 2,2 ); + + + tensor_type r1 = ublas::real( (a+a) / complex_type( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::real( l ); } ); + BOOST_CHECK( r0 == r1 ); + + tensor_type r2 = ublas::imag( (a+a) / complex_type( 2,2 ) ); + std::transform( b.begin(), b.end(), r0.begin(), [](auto const& l){ return std::imag( l ); } ); + BOOST_CHECK( r0 == r2 ); + + tensor_complex_type r3 = ublas::conj( (a+a) / complex_type( 2,2 ) ); + std::transform( b.begin(), b.end(), r00.begin(), [](auto const& l){ return std::conj( l ); } ); + BOOST_CHECK( r00 == r3 ); + + + + } + + + +} + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer_prod, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + for(auto const& n1 : extents) { + auto a = tensor_type(n1, value_type(2)); + for(auto const& n2 : extents) { + + auto b = tensor_type(n2, value_type(1)); + auto c = ublas::outer_prod(a, b); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + } +} + + + +template<class V> +void init(std::vector<V>& a) +{ + auto v = V(1); + for(auto i = 0u; i < a.size(); ++i, ++v){ + a[i] = v; + } +} + +template<class V> +void init(std::vector<std::complex<V>>& a) +{ + auto v = std::complex<V>(1,1); + for(auto i = 0u; i < a.size(); ++i){ + a[i] = v; + v.real(v.real()+1); + v.imag(v.imag()+1); + } +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_trans, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type,layout_type>; + + auto fak = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + auto inverse = [](auto const& pi){ + auto pi_inv = pi; + for(auto j = 0u; j < pi.size(); ++j) + pi_inv[pi[j]-1] = j+1; + return pi_inv; + }; + + for(auto const& n : extents) + { + auto const p = n.size(); + auto const s = n.product(); + auto aref = tensor_type(n); + auto v = value_type{}; + for(auto i = 0u; i < s; ++i, v+=1) + aref[i] = v; + auto a = aref; + + + auto pi = std::vector<std::size_t>(p); + std::iota(pi.begin(), pi.end(), 1); + a = ublas::trans( a, pi ); + BOOST_CHECK( a == aref ); + + + auto const pfak = fak(p); + auto i = 0u; + for(; i < pfak-1; ++i) { + std::next_permutation(pi.begin(), pi.end()); + a = ublas::trans( a, pi ); + } + std::next_permutation(pi.begin(), pi.end()); + for(; i > 0; --i) { + std::prev_permutation(pi.begin(), pi.end()); + auto pi_inv = inverse(pi); + a = ublas::trans( a, pi_inv ); + } + + BOOST_CHECK( a == aref ); + + } +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_multi_index.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_multi_index.cpp new file mode 100644 index 00000000..d6448de2 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_multi_index.cpp @@ -0,0 +1,146 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + +#include <iostream> +#include <algorithm> +#include <complex> +#include <boost/numeric/ublas/tensor.hpp> +#include <boost/numeric/ublas/tensor/multi_index.hpp> + + +#include <boost/test/unit_test.hpp> + +#include "utility.hpp" + + +BOOST_AUTO_TEST_SUITE ( test_multi_index ) + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + + +BOOST_AUTO_TEST_CASE ( test_index_classes ) +{ + using namespace boost::numeric::ublas::index; + + + BOOST_CHECK_EQUAL ( _a.value , 1 ) ; + BOOST_CHECK_EQUAL ( _b.value , 2 ) ; + BOOST_CHECK_EQUAL ( _c.value , 3 ) ; + BOOST_CHECK_EQUAL ( _d.value , 4 ) ; + BOOST_CHECK_EQUAL ( _e.value , 5 ) ; + BOOST_CHECK_EQUAL ( _f.value , 6 ) ; + BOOST_CHECK_EQUAL ( _g.value , 7 ) ; + BOOST_CHECK_EQUAL ( _h.value , 8 ) ; + BOOST_CHECK_EQUAL ( _i.value , 9 ) ; + BOOST_CHECK_EQUAL ( _j.value , 10 ) ; + BOOST_CHECK_EQUAL ( _k.value , 11 ) ; + BOOST_CHECK_EQUAL ( _l.value , 12 ) ; + BOOST_CHECK_EQUAL ( _m.value , 13 ) ; + BOOST_CHECK_EQUAL ( _n.value , 14 ) ; + BOOST_CHECK_EQUAL ( _o.value , 15 ) ; + BOOST_CHECK_EQUAL ( _p.value , 16 ) ; + BOOST_CHECK_EQUAL ( _q.value , 17 ) ; + BOOST_CHECK_EQUAL ( _r.value , 18 ) ; + BOOST_CHECK_EQUAL ( _s.value , 19 ) ; + BOOST_CHECK_EQUAL ( _t.value , 20 ) ; + BOOST_CHECK_EQUAL ( _u.value , 21 ) ; + BOOST_CHECK_EQUAL ( _v.value , 22 ) ; + BOOST_CHECK_EQUAL ( _w.value , 23 ) ; + BOOST_CHECK_EQUAL ( _x.value , 24 ) ; + BOOST_CHECK_EQUAL ( _y.value , 25 ) ; + BOOST_CHECK_EQUAL ( _z.value , 26 ) ; + +} + +BOOST_AUTO_TEST_CASE ( test_multi_index_class_construction ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + + { + multi_index<2> ind(_a, _b); + + BOOST_CHECK_EQUAL ( get<0>( ind ), 1 ) ; + BOOST_CHECK_EQUAL ( get<1>( ind ), 2 ) ; + } + + + { + multi_index<2> ind(_d,_c); + + BOOST_CHECK_EQUAL ( ind[0] , 4 ) ; + BOOST_CHECK_EQUAL ( ind[1] , 3 ) ; + } +} + + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_multi_index_class_generation, value, test_types ) +{ + using namespace boost::numeric::ublas; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = tensor<value_type,layout_type>; + + auto t = std::make_tuple ( + index::_a, // 0 + index::_b, // 1 + index::_c, // 2 + index::_d, // 3 + index::_e // 4 + ); + + { + auto a = tensor_type(shape{2,3}, value_type{2}); + auto a_ind = a( std::get<0>(t), std::get<2>(t) ); + + BOOST_CHECK_EQUAL ( std::addressof( a_ind.first ), std::addressof( a ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), index::_a() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_c() ) ; + } + + { + auto a = tensor_type(shape{2,3}, value_type{2}); + auto a_ind = a( std::get<2>(t), std::get<0>(t) ); + + BOOST_CHECK_EQUAL ( std::addressof( a_ind.first ), std::addressof( a ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), index::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_a() ) ; + } + + { + auto a = tensor_type(shape{2,3}, value_type{2}); + auto a_ind = a( std::get<2>(t), std::get<3>(t) ); + + BOOST_CHECK_EQUAL (std::addressof( a_ind.first ), std::addressof( a ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), index::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_d() ) ; + } + + { + auto a = tensor_type(shape{2,3,4}, value_type{2}); + auto a_ind = a( std::get<2>(t), std::get<3>(t), std::get<0>(t) ); + + BOOST_CHECK_EQUAL (std::addressof( a_ind.first ), std::addressof( a ) ) ; + + BOOST_CHECK_EQUAL (std::get<0>(a_ind.second)(), index::_c() ) ; + BOOST_CHECK_EQUAL (std::get<1>(a_ind.second)(), index::_d() ) ; + BOOST_CHECK_EQUAL (std::get<2>(a_ind.second)(), index::_a() ) ; + } + +} + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_multi_index_utility.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_multi_index_utility.cpp new file mode 100644 index 00000000..2f31a58f --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_multi_index_utility.cpp @@ -0,0 +1,564 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The author gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + +#include <boost/numeric/ublas/tensor.hpp> + +#include <boost/test/unit_test.hpp> + +BOOST_AUTO_TEST_SUITE ( test_multi_index_utility ) + + +BOOST_AUTO_TEST_CASE ( test_multi_index_has_index ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto has_a = has_index<decltype(_a),decltype(tuple)>::value; + constexpr auto has_b = has_index<decltype(_b),decltype(tuple)>::value; + BOOST_CHECK( !has_a ); + BOOST_CHECK( !has_b ); + } + + + { + constexpr auto tuple = std::make_tuple(_a); + constexpr auto has_a = has_index<decltype(_a),decltype(tuple)>::value; + constexpr auto has_b = has_index<decltype(_b),decltype(tuple)>::value; + BOOST_CHECK( has_a ); + BOOST_CHECK( !has_b ); + } + + { + constexpr auto tuple = std::make_tuple(_a,_b,_,_c,_d); + constexpr auto has_a = has_index<decltype(_a),decltype(tuple)>::value; + constexpr auto has_b = has_index<decltype(_b),decltype(tuple)>::value; + constexpr auto has_c = has_index<decltype(_c),decltype(tuple)>::value; + constexpr auto has_d = has_index<decltype(_d),decltype(tuple)>::value; + constexpr auto has_e = has_index<decltype(_e),decltype(tuple)>::value; + constexpr auto has__ = has_index<decltype( _),decltype(tuple)>::value; + BOOST_CHECK( has_a ); + BOOST_CHECK( has_b ); + BOOST_CHECK( has_c ); + BOOST_CHECK( has_d ); + BOOST_CHECK( !has_e ); + BOOST_CHECK( has__ ); + } +} + + + +BOOST_AUTO_TEST_CASE ( test_multi_index_valid ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } + + + { + constexpr auto tuple = std::make_tuple(_a); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_a,_,_b); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_a,_,_b,_b); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( !valid ); + } + + { + constexpr auto tuple = std::make_tuple(_c,_a,_,_b,_b); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( !valid ); + } + + { + constexpr auto tuple = std::make_tuple(_c,_a,_,_b); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } + + { + constexpr auto tuple = std::make_tuple(_,_c,_a,_,_b,_); + constexpr auto valid = valid_multi_index<decltype(tuple)>::value; + BOOST_CHECK( valid ); + } +} + + + + + +BOOST_AUTO_TEST_CASE ( test_multi_index_number_equal_indices ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto lhs = std::tuple<>{}; + constexpr auto rhs = std::tuple<>{}; + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::tuple<>{}; + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + { + constexpr auto lhs = std::tuple<>{}; + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_b); + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 0 ); + } + + + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_a,_b); + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_b); + constexpr auto rhs = std::make_tuple(_a,_b); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::make_tuple(_a); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } + + + + { + constexpr auto lhs = std::make_tuple(_a,_b); + constexpr auto rhs = std::make_tuple(_a,_b); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a); + constexpr auto rhs = std::make_tuple(_a,_b); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_c); + constexpr auto rhs = std::make_tuple(_a,_b); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_c); + constexpr auto rhs = std::make_tuple(_a,_b,_d); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d); + constexpr auto rhs = std::make_tuple(_a,_b,_d); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 3 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d); + constexpr auto rhs = std::make_tuple(_a,_b,_d,_); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 3 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d,_); + constexpr auto rhs = std::make_tuple(_a,_b,_d,_); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 3 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d,_); + constexpr auto rhs = std::make_tuple( _,_b,_d,_); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_,_a,_d,_); + constexpr auto rhs = std::make_tuple(_,_b,_d,_); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_,_a,_d,_); + constexpr auto rhs = std::make_tuple(_,_b,_d,_,_); + constexpr auto num = number_equal_indexes<decltype(lhs), decltype(rhs)>::value; + BOOST_CHECK_EQUAL( num, 1 ); + } +} + + + + + + + +BOOST_AUTO_TEST_CASE ( test_multi_index_index_position ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto tuple = std::tuple<>{}; + constexpr auto ind = index_position<decltype(_),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_); + constexpr auto ind = index_position<decltype(_),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_); + constexpr auto ind = index_position<decltype(_a),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position<decltype(_),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position<decltype(_a),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_,_a); + constexpr auto ind = index_position<decltype(_b),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,2); + } + + + + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position<decltype(_c),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,0); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a,_); + constexpr auto ind = index_position<decltype(_),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,1); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position<decltype(_a),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,2); + } + + { + constexpr auto tuple = std::make_tuple(_c,_,_a); + constexpr auto ind = index_position<decltype(_d),decltype(tuple)>::value; + BOOST_CHECK_EQUAL(ind,3); + } + +} + + + + + + + + +BOOST_AUTO_TEST_CASE ( test_multi_index_index_position_pairs ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + { + constexpr auto lhs = std::tuple<>{}; + constexpr auto rhs = std::tuple<>{}; + auto array = index_position_pairs(lhs, rhs); + BOOST_CHECK_EQUAL(array.size(), 0ul ); + } + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::tuple<>{}; + auto array = index_position_pairs(lhs, rhs); + BOOST_CHECK_EQUAL(array.size(), 0ul ); + } + + { + constexpr auto lhs = std::tuple<>{}; + constexpr auto rhs = std::make_tuple(_a); + auto array = index_position_pairs(lhs, rhs); + BOOST_CHECK_EQUAL(array.size(), 0ul ); + } + + { + constexpr auto lhs = std::make_tuple(_b); + constexpr auto rhs = std::make_tuple(_a); + auto array = index_position_pairs(lhs, rhs); + BOOST_CHECK_EQUAL(array.size(), 0ul ); + } + + + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::make_tuple(_a); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_a,_b); + constexpr auto rhs = std::make_tuple(_a); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_b); + constexpr auto rhs = std::make_tuple(_a,_b); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_a); + constexpr auto rhs = std::make_tuple(_a); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 0 ); + } + + + + { + constexpr auto lhs = std::make_tuple(_a,_b); + constexpr auto rhs = std::make_tuple(_a,_b); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 2ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 0 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 1 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a); + constexpr auto rhs = std::make_tuple(_a,_b); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 2ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_c); + constexpr auto rhs = std::make_tuple(_a,_b); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 2ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_c); + constexpr auto rhs = std::make_tuple(_a,_b,_d); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 2ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d); + constexpr auto rhs = std::make_tuple(_a,_b,_d); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 3ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + BOOST_CHECK_EQUAL(array[2].first , 2 ); + BOOST_CHECK_EQUAL(array[2].second, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d); + constexpr auto rhs = std::make_tuple(_a,_b,_d,_); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 3ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + BOOST_CHECK_EQUAL(array[2].first , 2 ); + BOOST_CHECK_EQUAL(array[2].second, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d,_); + constexpr auto rhs = std::make_tuple(_a,_b,_d,_); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 3ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 1 ); + BOOST_CHECK_EQUAL(array[1].second, 0 ); + BOOST_CHECK_EQUAL(array[2].first , 2 ); + BOOST_CHECK_EQUAL(array[2].second, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_b,_a,_d,_); + constexpr auto rhs = std::make_tuple( _,_b,_d,_); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 2ul ); + BOOST_CHECK_EQUAL(array[0].first , 0 ); + BOOST_CHECK_EQUAL(array[0].second, 1 ); + BOOST_CHECK_EQUAL(array[1].first , 2 ); + BOOST_CHECK_EQUAL(array[1].second, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_,_a,_d,_); + constexpr auto rhs = std::make_tuple(_,_b,_d,_); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 2 ); + BOOST_CHECK_EQUAL(array[0].second, 2 ); + } + + { + constexpr auto lhs = std::make_tuple(_,_a,_d,_); + constexpr auto rhs = std::make_tuple(_,_b,_d,_,_); + auto array = index_position_pairs(lhs, rhs); + BOOST_ASSERT(array.size() == 1ul ); + BOOST_CHECK_EQUAL(array[0].first , 2 ); + BOOST_CHECK_EQUAL(array[0].second, 2 ); + } +} + + + +BOOST_AUTO_TEST_CASE ( test_multi_index_array_to_vector ) +{ + using namespace boost::numeric::ublas; + using namespace boost::numeric::ublas::index; + + auto check = [](auto const& lhs, auto const& rhs) + { + auto array = index_position_pairs(lhs, rhs); + + auto vector_pair = array_to_vector( array ); + + BOOST_CHECK_EQUAL(vector_pair.first .size(), array.size() ); + BOOST_CHECK_EQUAL(vector_pair.second.size(), array.size() ); + + for(auto i = 0ul; i < array.size(); ++i) + { + BOOST_CHECK_EQUAL(vector_pair.first [i], array[i].first +1 ); + BOOST_CHECK_EQUAL(vector_pair.second[i], array[i].second+1 ); + } + + }; + + check(std::tuple<>{} , std::tuple<>{}); + check(std::make_tuple(_a) , std::tuple<>{}); + check(std::tuple<>{} , std::make_tuple(_a)); + check(std::make_tuple(_a) , std::make_tuple(_b)); + check(std::make_tuple(_a) , std::make_tuple(_a)); + check(std::make_tuple(_a,_b), std::make_tuple(_a)); + check(std::make_tuple(_a) , std::make_tuple(_a,_b)); + check(std::make_tuple(_a,_b), std::make_tuple(_a,_b)); + check(std::make_tuple(_b,_a), std::make_tuple(_a,_b)); + check(std::make_tuple(_b,_a,_c), std::make_tuple(_a,_b,_d)); +} + + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_multiplication.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_multiplication.cpp new file mode 100644 index 00000000..2f1570d1 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_multiplication.cpp @@ -0,0 +1,491 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + +#include <iostream> +#include <algorithm> +#include <vector> + +#include <boost/numeric/ublas/tensor/multiplication.hpp> +#include <boost/numeric/ublas/tensor/extents.hpp> +#include <boost/numeric/ublas/tensor/strides.hpp> +#include "utility.hpp" + +#include <boost/test/unit_test.hpp> + + +BOOST_AUTO_TEST_SUITE (test_tensor_contraction) + + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +//using test_types = zip<int>::with_t<boost::numeric::ublas::first_order>; + + +struct fixture +{ + using extents_type = boost::numeric::ublas::shape; + fixture() + : extents { + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{5,4}, // 5 + extents_type{2,3,1}, // 6 + extents_type{4,1,3}, // 7 + extents_type{1,2,3}, // 8 + extents_type{4,2,3}, // 9 + extents_type{4,2,3,5}} // 10 + { + } + std::vector<extents_type> extents; +}; + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_tensor_mtv, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + using extents_type_base = typename extents_type::base_type; + using size_type = typename extents_type_base::value_type; + + + for(auto const& na : extents) { + + if(na.size() > 2) + continue; + + auto a = vector_type(na.product(), value_type{2}); + auto wa = strides_type(na); + for(auto m = 0u; m < na.size(); ++m){ + auto nb = extents_type {na[m],1}; + auto wb = strides_type (nb); + auto b = vector_type (nb.product(), value_type{1} ); + + auto nc_base = extents_type_base(std::max(na.size()-1, size_type{2}), 1); + + for(auto i = 0u, j = 0u; i < na.size(); ++i) + if(i != m) + nc_base[j++] = na[i]; + + auto nc = extents_type (nc_base); + auto wc = strides_type (nc); + auto c = vector_type (nc.product(), value_type{0}); + + ublas::detail::recursive::mtv( + size_type(m), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data()); + + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type(na[m]) * a[i] ); + + } + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_mtm, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + // using extents_type_base = typename extents_type::base_type; + + + for(auto const& na : extents) { + + if(na.size() != 2) + continue; + + auto a = vector_type (na.product(), value_type{2}); + auto wa = strides_type (na); + + auto nb = extents_type {na[1],na[0]}; + auto wb = strides_type (nb); + auto b = vector_type (nb.product(), value_type{1} ); + + auto nc = extents_type {na[0],nb[1]}; +auto wc = strides_type (nc); +auto c = vector_type (nc.product()); + + +ublas::detail::recursive::mtm( + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + +for(auto i = 0u; i < c.size(); ++i) +BOOST_CHECK_EQUAL( c[i] , value_type(na[1]) * a[0] ); + + +} +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttv, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + using extents_type_base = typename extents_type::base_type; + using size_type = typename extents_type_base::value_type; + + + for(auto const& na : extents) { + + auto a = vector_type(na.product(), value_type{2}); + auto wa = strides_type(na); + for(auto m = 0u; m < na.size(); ++m){ + auto b = vector_type (na[m], value_type{1} ); + auto nb = extents_type {na[m],1}; + auto wb = strides_type (nb); + + auto nc_base = extents_type_base(std::max(na.size()-1, size_type(2)),1); + + for(auto i = 0ul, j = 0ul; i < na.size(); ++i) + if(i != m) + nc_base[j++] = na[i]; + + auto nc = extents_type (nc_base); + auto wc = strides_type (nc); + auto c = vector_type (nc.product(), value_type{0}); + + ublas::ttv(size_type(m+1), na.size(), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type(na[m]) * a[i] ); + + } + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttm, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + using size_type = typename extents_type::value_type; + + + for(auto const& na : extents) { + + auto a = vector_type(na.product(), value_type{2}); + auto wa = strides_type(na); + for(auto m = 0u; m < na.size(); ++m){ + auto nb = extents_type {na[m], na[m] }; + auto b = vector_type (nb.product(), value_type{1} ); + auto wb = strides_type (nb); + + + auto nc = na; + auto wc = strides_type (nc); + auto c = vector_type (nc.product(), value_type{0}); + + ublas::ttm(size_type(m+1), na.size(), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , value_type(na[m]) * a[i] ); + + } + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt_permutation, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + using size_type = typename strides_type::value_type; + + + auto compute_factorial = [](auto const& p){ + auto f = 1ul; + for(auto i = 1u; i <= p; ++i) + f *= i; + return f; + }; + + + auto compute_inverse_permutation = [](auto const& pi){ + auto pi_inv = pi; + for(auto j = 0u; j < pi.size(); ++j) + pi_inv[pi[j]-1] = j+1; + return pi_inv; + }; + + auto permute_extents = [](auto const& pi, auto const& na){ + auto nb = na; + assert(pi.size() == na.size()); + for(auto j = 0u; j < pi.size(); ++j) + nb[j] = na[pi[j]-1]; + return nb; + }; + + + // left-hand and right-hand side have the + // the same number of elements + + // computing the inner product with + // different permutation tuples for + // right-hand side + + for(auto const& na : extents) { + + auto wa = strides_type(na); + auto a = vector_type(na.product(), value_type{2}); + auto pa = na.size(); + auto pia = std::vector<size_type>(pa); + std::iota( pia.begin(), pia.end(), 1 ); + + auto pib = pia; + auto pib_inv = compute_inverse_permutation(pib); + + auto f = compute_factorial(pa); + + // for the number of possible permutations + // only permutation tuple pib is changed. + for(auto i = 0u; i < f; ++i) { + + auto nb = permute_extents( pib, na ); + auto wb = strides_type(nb); + auto b = vector_type(nb.product(), value_type{3}); + auto pb = nb.size(); + + // the number of contractions is changed. + for( auto q = size_type(0); q <= pa; ++q) { + + auto r = pa - q; + auto s = pb - q; + + auto pc = r+s > 0 ? std::max(r+s,size_type(2)) : size_type(2); + + auto nc_base = std::vector<size_type>( pc , 1 ); + + for(auto i = 0u; i < r; ++i) + nc_base[ i ] = na[ pia[i]-1 ]; + + for(auto i = 0u; i < s; ++i) + nc_base[ r + i ] = nb[ pib_inv[i]-1 ]; + + auto nc = extents_type ( nc_base ); + auto wc = strides_type ( nc ); + auto c = vector_type ( nc.product(), value_type(0) ); + + ublas::ttt(pa,pb,q, + pia.data(), pib_inv.data(), + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + + auto acc = value_type(1); + for(auto i = r; i < pa; ++i) + acc *= value_type(na[pia[i]-1]); + + for(auto i = 0ul; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + } + + std::next_permutation(pib.begin(), pib.end()); + pib_inv = compute_inverse_permutation(pib); + } + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ttt, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + using extents_type = ublas::shape; + using size_type = typename strides_type::value_type; + + // left-hand and right-hand side have the + // the same number of elements + + // computing the inner product with + // different permutation tuples for + // right-hand side + + for(auto const& na : extents) { + + auto wa = strides_type(na); + auto a = vector_type(na.product(), value_type{2}); + auto pa = na.size(); + + auto nb = na; + auto wb = strides_type(nb); + auto b = vector_type(nb.product(), value_type{3}); + auto pb = nb.size(); + + // std::cout << "na = "; + // std::copy(na.begin(), na.end(), std::ostream_iterator<size_type>(std::cout, " ")); + // std::cout << std::endl; + + // std::cout << "nb = "; + // std::copy(nb.begin(), nb.end(), std::ostream_iterator<size_type>(std::cout, " ")); + // std::cout << std::endl; + + + // the number of contractions is changed. + for( auto q = size_type(0); q <= pa; ++q) { // pa + + auto r = pa - q; + auto s = pb - q; + + auto pc = r+s > 0 ? std::max(r+s, size_type(2)) : size_type(2); + + auto nc_base = std::vector<size_type>( pc , 1 ); + + for(auto i = 0u; i < r; ++i) + nc_base[ i ] = na[ i ]; + + for(auto i = 0u; i < s; ++i) + nc_base[ r + i ] = nb[ i ]; + + auto nc = extents_type ( nc_base ); + auto wc = strides_type ( nc ); + auto c = vector_type ( nc.product(), value_type{0} ); + + // std::cout << "nc = "; + // std::copy(nc.begin(), nc.end(), std::ostream_iterator<size_type>(std::cout, " ")); + // std::cout << std::endl; + + ublas::ttt(pa,pb,q, + c.data(), nc.data(), wc.data(), + a.data(), na.data(), wa.data(), + b.data(), nb.data(), wb.data()); + + + auto acc = value_type(1); + for(auto i = r; i < pa; ++i) + acc *= value_type(na[i]); + + for(auto i = 0u; i < c.size(); ++i) + BOOST_CHECK_EQUAL( c[i] , acc * a[0] * b[0] ); + + } + + } +} + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_inner, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + + + for(auto const& n : extents) { + + auto a = vector_type(n.product(), value_type{2}); + auto b = vector_type(n.product(), value_type{3}); + auto w = strides_type(n); + + auto c = ublas::inner(n.size(), n.data(), a.data(), w.data(), b.data(), w.data(), value_type(0)); + auto cref = std::inner_product(a.begin(), a.end(), b.begin(), value_type(0)); + + + BOOST_CHECK_EQUAL( c , cref ); + + } + +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_outer, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using extents_type = ublas::shape; + using strides_type = ublas::strides<layout_type>; + using vector_type = std::vector<value_type>; + + + for(auto const& na : extents) { + + auto a = vector_type(na.product(), value_type{2}); + auto wa = strides_type(na); + + for(auto const& nb : extents) { + + auto b = vector_type(nb.product(), value_type{3}); + auto wb = strides_type(nb); + + auto c = vector_type(nb.product()*na.product()); + auto nc = typename extents_type::base_type(na.size()+nb.size()); + + for(auto i = 0u; i < na.size(); ++i) + nc[i] = na[i]; + for(auto i = 0u; i < nb.size(); ++i) + nc[i+na.size()] = nb[i]; + + auto wc = strides_type(extents_type(nc)); + + ublas::outer(c.data(), nc.size(), nc.data(), wc.data(), + a.data(), na.size(), na.data(), wa.data(), + b.data(), nb.size(), nb.data(), wb.data()); + + for(auto const& cc : c) + BOOST_CHECK_EQUAL( cc , a[0]*b[0] ); + } + + } + +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_operators_arithmetic.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_operators_arithmetic.cpp new file mode 100644 index 00000000..8bab7619 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_operators_arithmetic.cpp @@ -0,0 +1,267 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + +#include <boost/numeric/ublas/tensor.hpp> + +#include <boost/test/unit_test.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include "utility.hpp" + + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip<int,long,float,double,double_extended>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +struct fixture +{ + using extents_type = boost::numeric::ublas::basic_extents<std::size_t>; + fixture() + : extents{ + extents_type{}, // 0 + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{4,1,3}, // 6 + extents_type{1,2,3}, // 7 + extents_type{4,2,3}, // 8 + extents_type{4,2,3,5}} // 9 + { + } + std::vector<extents_type> extents; +}; + +BOOST_AUTO_TEST_SUITE(test_tensor_arithmetic_operations, * boost::unit_test::depends_on("test_tensor")) + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_binary_arithmetic_operations, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + auto t = tensor_type (e); + auto t2 = tensor_type (e); + auto r = tensor_type (e); + auto v = value_type {}; + + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); + + r = t + t + t + t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 3*t(i) + t2(i) ); + + + r = t2 / (t+3) * (t+1) - t2; // r = ( t2/ ((t+3)*(t+1)) ) - t2 + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t2(i) / (t(i)+3)*(t(i)+1) - t2(i) ); + + r = 3+t2 / (t+3) * (t+1) * t - t2; // r = 3+( t2/ ((t+3)*(t+1)*t) ) - t2 + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 3+t2(i) / (t(i)+3)*(t(i)+1)*t(i) - t2(i) ); + + r = t2 - t + t2 - t; + + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 4 ); + + + r = tensor_type (e,1) + tensor_type (e,1); + + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2 ); + + r = t * t * t * t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), t(i)*t(i)*t(i)*t2(i) ); + + r = (t2/t2) * (t2/t2); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 1 ); + }; + + for(auto const& e : extents) + check(e); + + + BOOST_CHECK_NO_THROW ( tensor_type t = tensor_type(extents.at(0)) + tensor_type(extents.at(0)) ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(0)) + tensor_type(extents.at(2)), std::runtime_error ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(1)) + tensor_type(extents.at(2)), std::runtime_error ); + + +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_unary_arithmetic_operations, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + auto t = tensor_type (e); + auto t2 = tensor_type (e); + auto v = value_type {}; + + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); + + tensor_type r1 = t + 2 + t + 2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r1(i), 2*t(i) + 4 ); + + tensor_type r2 = 2 + t + 2 + t; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r2(i), 2*t(i) + 4 ); + + tensor_type r3 = (t-2) + (t-2); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r3(i), 2*t(i) - 4 ); + + tensor_type r4 = (t*2) * (3*t); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r4(i), 2*3*t(i)*t(i) ); + + tensor_type r5 = (t2*2) / (2*t2) * t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r5(i), (t2(i)*2) / (2*t2(i)) * t2(i) ); + + tensor_type r6 = (t2/2+1) / (2/t2+1) / t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r6(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); + + }; + + for(auto const& e : extents) + check(e); + + BOOST_CHECK_NO_THROW ( tensor_type t = tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(0)) ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(1)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + tensor_type(extents.at(1)), std::runtime_error ); + BOOST_CHECK_THROW ( tensor_type t = tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(1)), std::runtime_error ); +} + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_assign_arithmetic_operations, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + auto t = tensor_type (e); + auto t2 = tensor_type (e); + auto r = tensor_type (e); + auto v = value_type {}; + + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); + + r = t + 2; + r += t; + r += 2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); + + r = 2 + t; + r += t; + r += 2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) + 4 ); + + r = (t-2); + r += t; + r -= 2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*t(i) - 4 ); + + r = (t*2); + r *= 3; + r *= t; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), 2*3*t(i)*t(i) ); + + r = (t2*2); + r /= 2; + r /= t2; + r *= t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)*2) / (2*t2(i)) * t2(i) ); + + r = (t2/2+1); + r /= (2/t2+1); + r /= t2; + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( r(i), (t2(i)/2+1) / (2/t2(i)+1) / t2(i) ); + + tensor_type q = -r; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( q(i), -r(i) ); + + tensor_type p = +r; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL ( p(i), r(i) ); + }; + + for(auto const& e : extents) + check(e); + + auto r = tensor_type (extents.at(0)); + + BOOST_CHECK_NO_THROW ( r += tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(0)) ); + BOOST_CHECK_THROW ( r += tensor_type(extents.at(0)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); + BOOST_CHECK_THROW ( r += tensor_type(extents.at(1)) + 2 + tensor_type(extents.at(2)), std::runtime_error ); + BOOST_CHECK_THROW ( r += tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + tensor_type(extents.at(1)), std::runtime_error ); + BOOST_CHECK_THROW ( r += tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(2)) + 2 + tensor_type(extents.at(1)), std::runtime_error ); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_operators_comparison.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_operators_comparison.cpp new file mode 100644 index 00000000..f076e9c1 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_operators_comparison.cpp @@ -0,0 +1,246 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + +#include <boost/numeric/ublas/tensor/operators_comparison.hpp> +#include <boost/numeric/ublas/tensor/operators_arithmetic.hpp> +#include <boost/numeric/ublas/tensor/tensor.hpp> +#include <boost/test/unit_test.hpp> +#include <boost/multiprecision/cpp_bin_float.hpp> +#include "utility.hpp" + + +using double_extended = boost::multiprecision::cpp_bin_float_double_extended; + +using test_types = zip<int,long,float,double,double_extended>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +struct fixture { + using extents_type = boost::numeric::ublas::basic_extents<std::size_t>; + fixture() + : extents{ + extents_type{}, // 0 + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{4,1,3}, // 6 + extents_type{1,2,3}, // 7 + extents_type{4,2,3}, // 8 + extents_type{4,2,3,5}} // 9 + { + } + std::vector<extents_type> extents; +}; + +BOOST_AUTO_TEST_SUITE(test_tensor_comparison, * boost::unit_test::depends_on("test_tensor")) + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + auto t = tensor_type (e); + auto t2 = tensor_type (e); + auto v = value_type {}; + + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); + + BOOST_CHECK( t == t ); + BOOST_CHECK( t != t2 ); + + if(t.empty()) + return; + + BOOST_CHECK(!(t < t)); + BOOST_CHECK(!(t > t)); + BOOST_CHECK( t < t2 ); + BOOST_CHECK( t2 > t ); + BOOST_CHECK( t <= t ); + BOOST_CHECK( t >= t ); + BOOST_CHECK( t <= t2 ); + BOOST_CHECK( t2 >= t ); + BOOST_CHECK( t2 >= t2 ); + BOOST_CHECK( t2 >= t ); + }; + + for(auto const& e : extents) + check(e); + + auto e0 = extents.at(0); + auto e1 = extents.at(1); + auto e2 = extents.at(2); + + + auto b = false; + BOOST_CHECK_NO_THROW ( b = (tensor_type(e0) == tensor_type(e0))); + BOOST_CHECK_NO_THROW ( b = (tensor_type(e1) == tensor_type(e2))); + BOOST_CHECK_NO_THROW ( b = (tensor_type(e0) == tensor_type(e2))); + BOOST_CHECK_NO_THROW ( b = (tensor_type(e1) != tensor_type(e2))); + + BOOST_CHECK_THROW ( b = (tensor_type(e1) >= tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW ( b = (tensor_type(e1) <= tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW ( b = (tensor_type(e1) < tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW ( b = (tensor_type(e1) > tensor_type(e2)), std::runtime_error ); + +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_tensor_expressions, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + auto t = tensor_type (e); + auto t2 = tensor_type (e); + auto v = value_type {}; + + std::iota(t.begin(), t.end(), v); + std::iota(t2.begin(), t2.end(), v+2); + + BOOST_CHECK( t == t ); + BOOST_CHECK( t != t2 ); + + if(t.empty()) + return; + + BOOST_CHECK( !(t < t) ); + BOOST_CHECK( !(t > t) ); + BOOST_CHECK( t < (t2+t) ); + BOOST_CHECK( (t2+t) > t ); + BOOST_CHECK( t <= (t+t) ); + BOOST_CHECK( (t+t2) >= t ); + BOOST_CHECK( (t2+t2+2) >= t); + BOOST_CHECK( 2*t2 > t ); + BOOST_CHECK( t < 2*t2 ); + BOOST_CHECK( 2*t2 > t); + BOOST_CHECK( 2*t2 >= t2 ); + BOOST_CHECK( t2 <= 2*t2); + BOOST_CHECK( 3*t2 >= t ); + + }; + + for(auto const& e : extents) + check(e); + + auto e0 = extents.at(0); + auto e1 = extents.at(1); + auto e2 = extents.at(2); + + auto b = false; + BOOST_CHECK_NO_THROW (b = tensor_type(e0) == (tensor_type(e0) + tensor_type(e0)) ); + BOOST_CHECK_NO_THROW (b = tensor_type(e1) == (tensor_type(e2) + tensor_type(e2)) ); + BOOST_CHECK_NO_THROW (b = tensor_type(e0) == (tensor_type(e2) + 2) ); + BOOST_CHECK_NO_THROW (b = tensor_type(e1) != (2 + tensor_type(e2)) ); + + BOOST_CHECK_NO_THROW (b = (tensor_type(e0) + tensor_type(e0)) == tensor_type(e0) ); + BOOST_CHECK_NO_THROW (b = (tensor_type(e2) + tensor_type(e2)) == tensor_type(e1) ); + BOOST_CHECK_NO_THROW (b = (tensor_type(e2) + 2) == tensor_type(e0) ); + BOOST_CHECK_NO_THROW (b = (2 + tensor_type(e2)) != tensor_type(e1) ); + + BOOST_CHECK_THROW (b = tensor_type(e1) >= (tensor_type(e2) + tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) <= (tensor_type(e2) + tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) < (tensor_type(e2) + tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) > (tensor_type(e2) + tensor_type(e2)), std::runtime_error ); + + BOOST_CHECK_THROW (b = tensor_type(e1) >= (tensor_type(e2) + 2), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) <= (2 + tensor_type(e2)), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) < (tensor_type(e2) + 3), std::runtime_error ); + BOOST_CHECK_THROW (b = tensor_type(e1) > (4 + tensor_type(e2)), std::runtime_error ); + +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_comparison_with_scalar, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + auto check = [](auto const& e) + { + + BOOST_CHECK( tensor_type(e,value_type{2}) == tensor_type(e,value_type{2}) ); + BOOST_CHECK( tensor_type(e,value_type{2}) != tensor_type(e,value_type{1}) ); + + if(e.empty()) + return; + + BOOST_CHECK( !(tensor_type(e,2) < 2) ); + BOOST_CHECK( !(tensor_type(e,2) > 2) ); + BOOST_CHECK( (tensor_type(e,2) >= 2) ); + BOOST_CHECK( (tensor_type(e,2) <= 2) ); + BOOST_CHECK( (tensor_type(e,2) == 2) ); + BOOST_CHECK( (tensor_type(e,2) != 3) ); + + BOOST_CHECK( !(2 > tensor_type(e,2)) ); + BOOST_CHECK( !(2 < tensor_type(e,2)) ); + BOOST_CHECK( (2 <= tensor_type(e,2)) ); + BOOST_CHECK( (2 >= tensor_type(e,2)) ); + BOOST_CHECK( (2 == tensor_type(e,2)) ); + BOOST_CHECK( (3 != tensor_type(e,2)) ); + + BOOST_CHECK( !( tensor_type(e,2)+3 < 5) ); + BOOST_CHECK( !( tensor_type(e,2)+3 > 5) ); + BOOST_CHECK( ( tensor_type(e,2)+3 >= 5) ); + BOOST_CHECK( ( tensor_type(e,2)+3 <= 5) ); + BOOST_CHECK( ( tensor_type(e,2)+3 == 5) ); + BOOST_CHECK( ( tensor_type(e,2)+3 != 6) ); + + + BOOST_CHECK( !( 5 > tensor_type(e,2)+3) ); + BOOST_CHECK( !( 5 < tensor_type(e,2)+3) ); + BOOST_CHECK( ( 5 >= tensor_type(e,2)+3) ); + BOOST_CHECK( ( 5 <= tensor_type(e,2)+3) ); + BOOST_CHECK( ( 5 == tensor_type(e,2)+3) ); + BOOST_CHECK( ( 6 != tensor_type(e,2)+3) ); + + + BOOST_CHECK( !( tensor_type(e,2)+tensor_type(e,3) < 5) ); + BOOST_CHECK( !( tensor_type(e,2)+tensor_type(e,3) > 5) ); + BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) >= 5) ); + BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) <= 5) ); + BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) == 5) ); + BOOST_CHECK( ( tensor_type(e,2)+tensor_type(e,3) != 6) ); + + + BOOST_CHECK( !( 5 > tensor_type(e,2)+tensor_type(e,3)) ); + BOOST_CHECK( !( 5 < tensor_type(e,2)+tensor_type(e,3)) ); + BOOST_CHECK( ( 5 >= tensor_type(e,2)+tensor_type(e,3)) ); + BOOST_CHECK( ( 5 <= tensor_type(e,2)+tensor_type(e,3)) ); + BOOST_CHECK( ( 5 == tensor_type(e,2)+tensor_type(e,3)) ); + BOOST_CHECK( ( 6 != tensor_type(e,2)+tensor_type(e,3)) ); + + }; + + for(auto const& e : extents) + check(e); + +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_strides.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_strides.cpp new file mode 100644 index 00000000..3a29e660 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_strides.cpp @@ -0,0 +1,172 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + + +#include <boost/test/unit_test.hpp> +#include <boost/numeric/ublas/tensor/strides.hpp> +#include <boost/numeric/ublas/tensor/extents.hpp> + +//BOOST_AUTO_TEST_SUITE(test_strides, * boost::unit_test::depends_on("test_extents")); + +BOOST_AUTO_TEST_SUITE(test_strides) + +using test_types = std::tuple<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_strides_ctor, value, test_types) +{ + using namespace boost::numeric; + + using extents_type = ublas::basic_extents<unsigned>; + using strides_type = ublas::strides<value>; + + strides_type s0{}; + BOOST_CHECK ( s0.empty()); + BOOST_CHECK_EQUAL ( s0.size(), 0); + + strides_type s1{extents_type{1,1}}; + BOOST_CHECK (!s1.empty()); + BOOST_CHECK_EQUAL ( s1.size(), 2); + + strides_type s2{extents_type{1,2}}; + BOOST_CHECK (!s2.empty()); + BOOST_CHECK_EQUAL ( s2.size(), 2); + + strides_type s3{extents_type{2,1}}; + BOOST_CHECK (!s3.empty()); + BOOST_CHECK_EQUAL ( s3.size(), 2); + + strides_type s4{extents_type{2,3}}; + BOOST_CHECK (!s4.empty()); + BOOST_CHECK_EQUAL ( s4.size(), 2); + + strides_type s5{extents_type{2,3,1}}; + BOOST_CHECK (!s5.empty()); + BOOST_CHECK_EQUAL ( s5.size(), 3); + + strides_type s6{extents_type{1,2,3}}; + BOOST_CHECK (!s6.empty()); + BOOST_CHECK_EQUAL ( s6.size(), 3); + + strides_type s7{extents_type{4,2,3}}; + BOOST_CHECK (!s7.empty()); + BOOST_CHECK_EQUAL ( s7.size(), 3); +} + + + +BOOST_AUTO_TEST_CASE( test_strides_ctor_access_first_order) +{ + using namespace boost::numeric; + + using extents_type = ublas::basic_extents<unsigned>; + using strides_type = ublas::strides<ublas::first_order>; + + strides_type s1{extents_type{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + strides_type s2{extents_type{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + strides_type s3{extents_type{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + strides_type s4{extents_type{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 1); + BOOST_CHECK_EQUAL ( s4[1], 2); + + strides_type s5{extents_type{2,3,1}}; + BOOST_REQUIRE_EQUAL ( s5.size(),3); + BOOST_CHECK_EQUAL ( s5[0], 1); + BOOST_CHECK_EQUAL ( s5[1], 2); + BOOST_CHECK_EQUAL ( s5[2], 6); + + strides_type s6{extents_type{1,2,3}}; + BOOST_REQUIRE_EQUAL ( s6.size(),3); + BOOST_CHECK_EQUAL ( s6[0], 1); + BOOST_CHECK_EQUAL ( s6[1], 1); + BOOST_CHECK_EQUAL ( s6[2], 2); + + strides_type s7{extents_type{2,1,3}}; + BOOST_REQUIRE_EQUAL ( s7.size(),3); + BOOST_CHECK_EQUAL ( s7[0], 1); + BOOST_CHECK_EQUAL ( s7[1], 2); + BOOST_CHECK_EQUAL ( s7[2], 2); + + strides_type s8{extents_type{4,2,3}}; + BOOST_REQUIRE_EQUAL ( s8.size(),3); + BOOST_CHECK_EQUAL ( s8[0], 1); + BOOST_CHECK_EQUAL ( s8[1], 4); + BOOST_CHECK_EQUAL ( s8[2], 8); +} + +BOOST_AUTO_TEST_CASE( test_strides_ctor_access_last_order) +{ + using namespace boost::numeric; + + using extents_type = ublas::basic_extents<unsigned>; + using strides_type = ublas::strides<ublas::last_order>; + + strides_type s1{extents_type{1,1}}; + BOOST_REQUIRE_EQUAL( s1.size(),2); + BOOST_CHECK_EQUAL ( s1[0], 1); + BOOST_CHECK_EQUAL ( s1[1], 1); + + strides_type s2{extents_type{1,2}}; + BOOST_REQUIRE_EQUAL ( s2.size(),2); + BOOST_CHECK_EQUAL ( s2[0], 1); + BOOST_CHECK_EQUAL ( s2[1], 1); + + strides_type s3{extents_type{2,1}}; + BOOST_REQUIRE_EQUAL ( s3.size(),2); + BOOST_CHECK_EQUAL ( s3[0], 1); + BOOST_CHECK_EQUAL ( s3[1], 1); + + strides_type s4{extents_type{2,3}}; + BOOST_REQUIRE_EQUAL ( s4.size(),2); + BOOST_CHECK_EQUAL ( s4[0], 3); + BOOST_CHECK_EQUAL ( s4[1], 1); + + strides_type s5{extents_type{2,3,1}}; + BOOST_REQUIRE_EQUAL ( s5.size(),3); + BOOST_CHECK_EQUAL ( s5[0], 3); + BOOST_CHECK_EQUAL ( s5[1], 1); + BOOST_CHECK_EQUAL ( s5[2], 1); + + strides_type s6{extents_type{1,2,3}}; + BOOST_REQUIRE_EQUAL ( s6.size(),3); + BOOST_CHECK_EQUAL ( s6[0], 6); + BOOST_CHECK_EQUAL ( s6[1], 3); + BOOST_CHECK_EQUAL ( s6[2], 1); + + strides_type s7{extents_type{2,1,3}}; + BOOST_REQUIRE_EQUAL ( s7.size(),3); + BOOST_CHECK_EQUAL ( s7[0], 3); + BOOST_CHECK_EQUAL ( s7[1], 3); + BOOST_CHECK_EQUAL ( s7[2], 1); + + strides_type s8{extents_type{4,2,3}}; + BOOST_REQUIRE_EQUAL ( s8.size(),3); + BOOST_CHECK_EQUAL ( s8[0], 6); + BOOST_CHECK_EQUAL ( s8[1], 3); + BOOST_CHECK_EQUAL ( s8[2], 1); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_tensor.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_tensor.cpp new file mode 100644 index 00000000..400e8624 --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_tensor.cpp @@ -0,0 +1,473 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + + +#include <random> +#include <boost/numeric/ublas/tensor/tensor.hpp> + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE TestTensor + +#include <boost/test/unit_test.hpp> +#include "utility.hpp" + +//BOOST_AUTO_TEST_SUITE ( test_tensor, * boost::unit_test::depends_on("test_extents") ) ; +BOOST_AUTO_TEST_SUITE ( test_tensor ) + +using test_types = zip<int,long,float,double,std::complex<float>>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_ctor, value, test_types) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto a1 = tensor_type{}; + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + auto a2 = tensor_type{1,1}; + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + auto a3 = tensor_type{2,1}; + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + auto a4 = tensor_type{1,2}; + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + auto a5 = tensor_type{2,1}; + BOOST_CHECK_EQUAL( a5.size() , 2 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); + + auto a6 = tensor_type{4,3,2}; + BOOST_CHECK_EQUAL( a6.size() , 4*3*2 ); + BOOST_CHECK( !a6.empty() ); + BOOST_CHECK_NE( a6.data() , nullptr); + + auto a7 = tensor_type{4,1,2}; + BOOST_CHECK_EQUAL( a7.size() , 4*1*2 ); + BOOST_CHECK( !a7.empty() ); + BOOST_CHECK_NE( a7.data() , nullptr); +} + + +struct fixture +{ + using extents_type = boost::numeric::ublas::basic_extents<std::size_t>; + fixture() + : extents { + extents_type{}, // 0 + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{2,3,1}, // 5 + extents_type{4,1,3}, // 6 + extents_type{1,2,3}, // 7 + extents_type{4,2,3}, // 8 + extents_type{4,2,3,5}} // 9 + { + } + std::vector<extents_type> extents; +}; + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto check = [](auto const& e) { + auto t = tensor_type{e}; + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + BOOST_CHECK_EQUAL ( t.data() , nullptr); + } + else{ + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + } + }; + + for(auto const& e : extents) + check(e); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto check = [](auto const& e) + { + auto r = tensor_type{e}; + auto t = r; + BOOST_CHECK_EQUAL ( t.size() , r.size() ); + BOOST_CHECK_EQUAL ( t.rank() , r.rank() ); + BOOST_CHECK ( t.strides() == r.strides() ); + BOOST_CHECK ( t.extents() == r.extents() ); + + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + BOOST_CHECK_EQUAL ( t.data() , nullptr); + } + else{ + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + } + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], r[i] ); + }; + + for(auto const& e : extents) + check(e); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_ctor_layout, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using other_layout_type = std::conditional_t<std::is_same<ublas::first_order,layout_type>::value, ublas::last_order, ublas::first_order>; + using other_tensor_type = ublas::tensor<value_type, other_layout_type>; + + + for(auto const& e : extents) + { + auto r = tensor_type{e}; + other_tensor_type t = r; + tensor_type q = t; + + BOOST_CHECK_EQUAL ( t.size() , r.size() ); + BOOST_CHECK_EQUAL ( t.rank() , r.rank() ); + BOOST_CHECK ( t.extents() == r.extents() ); + + BOOST_CHECK_EQUAL ( q.size() , r.size() ); + BOOST_CHECK_EQUAL ( q.rank() , r.rank() ); + BOOST_CHECK ( q.strides() == r.strides() ); + BOOST_CHECK ( q.extents() == r.extents() ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( q[i], r[i] ); + } +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_copy_move_ctor, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto check = [](auto const& e) + { + auto r = tensor_type{e}; + auto t = std::move(r); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + + if(e.empty()) { + BOOST_CHECK ( t.empty() ); + BOOST_CHECK_EQUAL ( t.data() , nullptr); + } + else{ + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + } + + }; + + for(auto const& e : extents) + check(e); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_init, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + std::random_device device{}; + std::minstd_rand0 generator(device()); + + using distribution_type = std::conditional_t<std::is_integral_v<value_type>, std::uniform_int_distribution<>, std::uniform_real_distribution<> >; + auto distribution = distribution_type(1,6); + + for(auto const& e : extents){ + auto r = static_cast<value_type>(distribution(generator)); + auto t = tensor_type{e,r}; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], r ); + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_ctor_extents_array, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using array_type = typename tensor_type::array_type; + + for(auto const& e : extents) { + auto a = array_type(e.product()); + auto v = value_type {}; + + for(auto& aa : a){ + aa = v; + v += value_type{1}; + } + auto t = tensor_type{e, a}; + v = value_type{}; + + for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1}) + BOOST_CHECK_EQUAL( t[i], v); + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_single_index_access, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + for(auto const& e : extents) { + auto t = tensor_type{e}; + auto v = value_type {}; + for(auto i = 0ul; i < t.size(); ++i, v+=value_type{1}){ + t[i] = v; + BOOST_CHECK_EQUAL( t[i], v ); + + t(i) = v; + BOOST_CHECK_EQUAL( t(i), v ); + } + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_read_write_multi_index_access_at, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + auto check1 = [](const tensor_type& t) + { + auto v = value_type{}; + for(auto k = 0ul; k < t.size(); ++k){ + BOOST_CHECK_EQUAL(t[k], v); + v+=value_type{1}; + } + }; + + auto check2 = [](const tensor_type& t) + { + std::array<unsigned,2> k; + auto r = std::is_same_v<layout_type,ublas::first_order> ? 1 : 0; + auto q = std::is_same_v<layout_type,ublas::last_order > ? 1 : 0; + auto v = value_type{}; + for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ + for(k[q] = 0ul; k[q] < t.size(q); ++k[q]){ + BOOST_CHECK_EQUAL(t.at(k[0],k[1]), v); + v+=value_type{1}; + } + } + }; + + auto check3 = [](const tensor_type& t) + { + std::array<unsigned,3> k; + using op_type = std::conditional_t<std::is_same_v<layout_type,ublas::first_order>, std::minus<>, std::plus<>>; + auto r = std::is_same_v<layout_type,ublas::first_order> ? 2 : 0; + auto o = op_type{}; + auto v = value_type{}; + for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ + for(k[o(r,1)] = 0ul; k[o(r,1)] < t.size(o(r,1)); ++k[o(r,1)]){ + for(k[o(r,2)] = 0ul; k[o(r,2)] < t.size(o(r,2)); ++k[o(r,2)]){ + BOOST_CHECK_EQUAL(t.at(k[0],k[1],k[2]), v); + v+=value_type{1}; + } + } + } + }; + + auto check4 = [](const tensor_type& t) + { + std::array<unsigned,4> k; + using op_type = std::conditional_t<std::is_same_v<layout_type,ublas::first_order>, std::minus<>, std::plus<>>; + auto r = std::is_same_v<layout_type,ublas::first_order> ? 3 : 0; + auto o = op_type{}; + auto v = value_type{}; + for(k[r] = 0ul; k[r] < t.size(r); ++k[r]){ + for(k[o(r,1)] = 0ul; k[o(r,1)] < t.size(o(r,1)); ++k[o(r,1)]){ + for(k[o(r,2)] = 0ul; k[o(r,2)] < t.size(o(r,2)); ++k[o(r,2)]){ + for(k[o(r,3)] = 0ul; k[o(r,3)] < t.size(o(r,3)); ++k[o(r,3)]){ + BOOST_CHECK_EQUAL(t.at(k[0],k[1],k[2],k[3]), v); + v+=value_type{1}; + } + } + } + } + }; + + auto check = [check1,check2,check3,check4](auto const& e) { + auto t = tensor_type{e}; + auto v = value_type {}; + for(auto i = 0ul; i < t.size(); ++i){ + t[i] = v; + v+=value_type{1}; + } + + if(t.rank() == 1) check1(t); + else if(t.rank() == 2) check2(t); + else if(t.rank() == 3) check3(t); + else if(t.rank() == 4) check4(t); + + }; + + for(auto const& e : extents) + check(e); +} + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_reshape, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + + for(auto const& efrom : extents){ + for(auto const& eto : extents){ + + auto v = value_type {}; + v+=value_type{1}; + auto t = tensor_type{efrom, v}; + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + t.reshape(eto); + for(auto i = 0ul; i < std::min(efrom.product(),eto.product()); ++i) + BOOST_CHECK_EQUAL( t[i], v ); + + BOOST_CHECK_EQUAL ( t.size() , eto.product() ); + BOOST_CHECK_EQUAL ( t.rank() , eto.size() ); + BOOST_CHECK ( t.extents() == eto ); + + if(efrom != eto){ + for(auto i = efrom.product(); i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], value_type{} ); + } + } + } +} + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_swap, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + for(auto const& e_t : extents){ + for(auto const& e_r : extents) { + + auto v = value_type {} + value_type{1}; + auto w = value_type {} + value_type{2}; + auto t = tensor_type{e_t, v}; + auto r = tensor_type{e_r, w}; + + std::swap( r, t ); + + for(auto i = 0ul; i < t.size(); ++i) + BOOST_CHECK_EQUAL( t[i], w ); + + BOOST_CHECK_EQUAL ( t.size() , e_r.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e_r.size() ); + BOOST_CHECK ( t.extents() == e_r ); + + for(auto i = 0ul; i < r.size(); ++i) + BOOST_CHECK_EQUAL( r[i], v ); + + BOOST_CHECK_EQUAL ( r.size() , e_t.product() ); + BOOST_CHECK_EQUAL ( r.rank() , e_t.size() ); + BOOST_CHECK ( r.extents() == e_t ); + + + } + } +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_standard_iterator, value, test_types, fixture) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + + for(auto const& e : extents) + { + auto v = value_type {} + value_type{1}; + auto t = tensor_type{e, v}; + + BOOST_CHECK_EQUAL( std::distance(t.begin(), t.end ()), t.size() ); + BOOST_CHECK_EQUAL( std::distance(t.rbegin(), t.rend()), t.size() ); + + BOOST_CHECK_EQUAL( std::distance(t.cbegin(), t.cend ()), t.size() ); + BOOST_CHECK_EQUAL( std::distance(t.crbegin(), t.crend()), t.size() ); + + if(t.size() > 0) { + BOOST_CHECK( t.data() == std::addressof( *t.begin () ) ) ; + BOOST_CHECK( t.data() == std::addressof( *t.cbegin() ) ) ; + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/boost/libs/numeric/ublas/test/tensor/test_tensor_matrix_vector.cpp b/src/boost/libs/numeric/ublas/test/tensor/test_tensor_matrix_vector.cpp new file mode 100644 index 00000000..3e34047d --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/test_tensor_matrix_vector.cpp @@ -0,0 +1,472 @@ +// Copyright (c) 2018-2019 Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + + +#include <iostream> +#include <random> +#include <boost/numeric/ublas/tensor.hpp> +#include <boost/numeric/ublas/matrix.hpp> +#include <boost/test/unit_test.hpp> + +#include "utility.hpp" + +// BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability, * boost::unit_test::depends_on("test_tensor") ) ; + +BOOST_AUTO_TEST_SUITE ( test_tensor_matrix_interoperability ) + +using test_types = zip<int,long,float,double>::with_t<boost::numeric::ublas::first_order, boost::numeric::ublas::last_order>; + + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor, value, test_types) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + tensor_type a1 = matrix_type(); + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + tensor_type a2 = matrix_type(1,1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + tensor_type a3 = matrix_type(2,1); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + tensor_type a4 = matrix_type(1,2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + tensor_type a5 = matrix_type(2,3); + BOOST_CHECK_EQUAL( a5.size() , 6 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); +} + + +BOOST_AUTO_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor, value, test_types) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using vector_type = typename tensor_type::vector_type; + + tensor_type a1 = vector_type(); + BOOST_CHECK_EQUAL( a1.size() , 0ul ); + BOOST_CHECK( a1.empty() ); + BOOST_CHECK_EQUAL( a1.data() , nullptr); + + tensor_type a2 = vector_type(1); + BOOST_CHECK_EQUAL( a2.size() , 1 ); + BOOST_CHECK( !a2.empty() ); + BOOST_CHECK_NE( a2.data() , nullptr); + + tensor_type a3 = vector_type(2); + BOOST_CHECK_EQUAL( a3.size() , 2 ); + BOOST_CHECK( !a3.empty() ); + BOOST_CHECK_NE( a3.data() , nullptr); + + tensor_type a4 = vector_type(2); + BOOST_CHECK_EQUAL( a4.size() , 2 ); + BOOST_CHECK( !a4.empty() ); + BOOST_CHECK_NE( a4.data() , nullptr); + + tensor_type a5 = vector_type(3); + BOOST_CHECK_EQUAL( a5.size() , 3 ); + BOOST_CHECK( !a5.empty() ); + BOOST_CHECK_NE( a5.data() , nullptr); +} + + +struct fixture +{ + using extents_type = boost::numeric::ublas::basic_extents<std::size_t>; + fixture() + : extents{ + extents_type{1,1}, // 1 + extents_type{1,2}, // 2 + extents_type{2,1}, // 3 + extents_type{2,3}, // 4 + extents_type{9,7}, // 5 + extents_type{9,11}, // 6 + extents_type{12,12}, // 7 + extents_type{15,17}} // 8 + { + } + std::vector<extents_type> extents; +}; + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_ctor_extents, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const& e) { + assert(e.size()==2); + tensor_type t = matrix_type{e[0],e[1]}; + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for(auto const& e : extents) + check(e); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_ctor_extents, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) { + assert(e.size()==2); + if(e.empty()) + return; + + tensor_type t = vector_type(e.product()); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + }; + + for(auto const& e : extents) + check(e); +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_copy_assignment, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r; + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) ); + BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) ); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_CHECK_EQUAL( t.at(i,j), r(i,j) ); + } + } + }; + + for(auto const& e : extents) + check(e); +} + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_copy_assignment, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r; + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0)*e.at(1) ); + BOOST_CHECK_EQUAL ( t.extents().at(1) , 1); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], r(i) ); + } + }; + + for(auto const& e : extents) + check(e); +} + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_move_assignment, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + auto q = r; + t = std::move(r); + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) ); + BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) ); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_CHECK_EQUAL( t.at(i,j), q(i,j) ); + } + } + }; + + for(auto const& e : extents) + check(e); +} + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_move_assignment, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + auto q = r; + t = std::move(r); + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) * e.at(1)); + BOOST_CHECK_EQUAL ( t.extents().at(1) , 1); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t[i], q(i) ); + } + }; + + for(auto const& e : extents) + check(e); +} + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_expressions, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = matrix_type(e[0],e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + tensor_type s = r + 3*r; + tensor_type q = s + r + 3*r + s; // + 3*r + + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0) ); + BOOST_CHECK_EQUAL ( t.extents().at(1) , e.at(1) ); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + BOOST_CHECK_EQUAL ( s.extents().at(0) , e.at(0) ); + BOOST_CHECK_EQUAL ( s.extents().at(1) , e.at(1) ); + BOOST_CHECK_EQUAL ( s.size() , e.product() ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + BOOST_CHECK_NE ( s.data() , nullptr); + + BOOST_CHECK_EQUAL ( q.extents().at(0) , e.at(0) ); + BOOST_CHECK_EQUAL ( q.extents().at(1) , e.at(1) ); + BOOST_CHECK_EQUAL ( q.size() , e.product() ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + BOOST_CHECK_NE ( q.data() , nullptr); + + + for(auto j = 0ul; j < t.size(1); ++j){ + for(auto i = 0ul; i < t.size(0); ++i){ + BOOST_CHECK_EQUAL( t.at(i,j), 4*r(i,j) ); + BOOST_CHECK_EQUAL( s.at(i,j), t.at(i,j) ); + BOOST_CHECK_EQUAL( q.at(i,j), 3*s.at(i,j) ); + } + } + }; + + for(auto const& e : extents) + check(e); +} + + + + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_vector_expressions, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) + { + assert(e.size() == 2); + auto t = tensor_type{}; + auto r = vector_type(e[0]*e[1]); + std::iota(r.data().begin(),r.data().end(), 1); + t = r + 3*r; + tensor_type s = r + 3*r; + tensor_type q = s + r + 3*r + s; // + 3*r + + + BOOST_CHECK_EQUAL ( t.extents().at(0) , e.at(0)*e.at(1) ); + BOOST_CHECK_EQUAL ( t.extents().at(1) , 1); + BOOST_CHECK_EQUAL ( t.size() , e.product() ); + BOOST_CHECK_EQUAL ( t.rank() , e.size() ); + BOOST_CHECK ( !t.empty() ); + BOOST_CHECK_NE ( t.data() , nullptr); + + BOOST_CHECK_EQUAL ( s.extents().at(0) , e.at(0)*e.at(1) ); + BOOST_CHECK_EQUAL ( s.extents().at(1) , 1); + BOOST_CHECK_EQUAL ( s.size() , e.product() ); + BOOST_CHECK_EQUAL ( s.rank() , e.size() ); + BOOST_CHECK ( !s.empty() ); + BOOST_CHECK_NE ( s.data() , nullptr); + + BOOST_CHECK_EQUAL ( q.extents().at(0) , e.at(0)*e.at(1) ); + BOOST_CHECK_EQUAL ( q.extents().at(1) , 1); + BOOST_CHECK_EQUAL ( q.size() , e.product() ); + BOOST_CHECK_EQUAL ( q.rank() , e.size() ); + BOOST_CHECK ( !q.empty() ); + BOOST_CHECK_NE ( q.data() , nullptr); + + + + for(auto i = 0ul; i < t.size(); ++i){ + BOOST_CHECK_EQUAL( t.at(i), 4*r(i) ); + BOOST_CHECK_EQUAL( s.at(i), t.at(i) ); + BOOST_CHECK_EQUAL( q.at(i), 3*s.at(i) ); + } + }; + + for(auto const& e : extents) + check(e); +} + + + +BOOST_FIXTURE_TEST_CASE_TEMPLATE( test_tensor_matrix_vector_expressions, value, test_types, fixture ) +{ + using namespace boost::numeric; + using value_type = typename value::first_type; + using layout_type = typename value::second_type; + using tensor_type = ublas::tensor<value_type, layout_type>; + using matrix_type = typename tensor_type::matrix_type; + using vector_type = typename tensor_type::vector_type; + + auto check = [](auto const& e) + { + if(e.product() <= 2) + return; + assert(e.size() == 2); + auto Q = tensor_type{e[0],1}; + auto A = matrix_type(e[0],e[1]); + auto b = vector_type(e[1]); + auto c = vector_type(e[0]); + std::iota(b.data().begin(),b.data().end(), 1); + std::fill(A.data().begin(),A.data().end(), 1); + std::fill(c.data().begin(),c.data().end(), 2); + std::fill(Q.begin(),Q.end(), 2); + + tensor_type T = Q + (ublas::prod(A , b) + 2*c) + 3*Q; + + BOOST_CHECK_EQUAL ( T.extents().at(0) , Q.extents().at(0) ); + BOOST_CHECK_EQUAL ( T.extents().at(1) , Q.extents().at(1)); + BOOST_CHECK_EQUAL ( T.size() , Q.size() ); + BOOST_CHECK_EQUAL ( T.size() , c.size() ); + BOOST_CHECK_EQUAL ( T.rank() , Q.rank() ); + BOOST_CHECK ( !T.empty() ); + BOOST_CHECK_NE ( T.data() , nullptr); + + for(auto i = 0ul; i < T.size(); ++i){ + auto n = e[1]; + auto ab = n * (n+1) / 2; + BOOST_CHECK_EQUAL( T(i), ab+4*Q(0)+2*c(0) ); + } + + }; + + + + for(auto const& e : extents) + check(e); +} + + +BOOST_AUTO_TEST_SUITE_END() + diff --git a/src/boost/libs/numeric/ublas/test/tensor/utility.hpp b/src/boost/libs/numeric/ublas/test/tensor/utility.hpp new file mode 100644 index 00000000..b2ef266e --- /dev/null +++ b/src/boost/libs/numeric/ublas/test/tensor/utility.hpp @@ -0,0 +1,56 @@ +// Copyright (c) 2018-2019 +// Cem Bassoy +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// The authors gratefully acknowledge the support of +// Fraunhofer and Google in producing this work +// which started as a Google Summer of Code project. +// + +#ifndef _BOOST_UBLAS_TEST_TENSOR_UTILITY_ +#define _BOOST_UBLAS_TEST_TENSOR_UTILITY_ + +template<class ... types> +struct zip_helper; + +template<class type1, class ... types3> +struct zip_helper<std::tuple<types3...>, type1> +{ + template<class ... types2> + struct with + { + using type = std::tuple<types3...,std::pair<type1,types2>...>; + }; + template<class ... types2> + using with_t = typename with<types2...>::type; +}; + + +template<class type1, class ... types3, class ... types1> +struct zip_helper<std::tuple<types3...>, type1, types1...> +{ + template<class ... types2> + struct with + { + using next_tuple = std::tuple<types3...,std::pair<type1,types2>...>; + using type = typename zip_helper<next_tuple, types1...>::template with<types2...>::type; + }; + + template<class ... types2> + using with_t = typename with<types2...>::type; +}; + +template<class ... types> +using zip = zip_helper<std::tuple<>,types...>; + +// creates e.g. +// using test_types = zip<long,float>::with_t<first_order,last_order>; // equals +// using test_types = std::tuple< std::pair<float, first_order>, std::pair<float, last_order >, std::pair<double,first_order>, std::pair<double,last_order > +//>; +//static_assert(std::is_same< std::tuple_element_t<0,std::tuple_element_t<0,test_types2>>, float>::value,"should be float "); +//static_assert(std::is_same< std::tuple_element_t<1,std::tuple_element_t<0,test_types2>>, boost::numeric::ublas::first_order>::value,"should be boost::numeric::ublas::first_order "); + +#endif |