[DEV] add v1.76.0

This commit is contained in:
2021-10-05 21:37:46 +02:00
parent a97e9ae7d4
commit d0115b733d
45133 changed files with 4744437 additions and 1026325 deletions

View File

@@ -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 ]
;

View File

@@ -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()

View File

@@ -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()

View File

@@ -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)) );
}
}

View File

@@ -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 ) ) );
}
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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